Add routes for media outlets, articles, and prediction markets

Adds API endpoints for fetching articles by media outlet slug, prediction markets by article slug, and auction data for media outlets. Includes functionality to place bids on media outlet auctions.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 069d4324-6c40-4355-955e-c714a50de1ea
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/3df548ff-50ae-432f-9be4-25d34eccc983/069d4324-6c40-4355-955e-c714a50de1ea/jvFIdY3
This commit is contained in:
kimjaehyeon0101
2025-09-29 19:01:59 +00:00
parent 020f212281
commit 8efbfc51d7
2 changed files with 97 additions and 1 deletions

View File

@ -55,6 +55,20 @@ export async function registerRoutes(app: Express): Promise<Server> {
} }
}); });
app.get('/api/media-outlets/:slug/articles', async (req, res) => {
try {
const outlet = await storage.getMediaOutletBySlug(req.params.slug);
if (!outlet) {
return res.status(404).json({ message: "Media outlet not found" });
}
const articles = await storage.getArticlesByOutlet(outlet.id);
res.json(articles);
} catch (error) {
console.error("Error fetching articles by slug:", error);
res.status(500).json({ message: "Failed to fetch articles" });
}
});
app.get('/api/articles/:slug', async (req, res) => { app.get('/api/articles/:slug', async (req, res) => {
try { try {
const article = await storage.getArticleBySlug(req.params.slug); const article = await storage.getArticleBySlug(req.params.slug);
@ -68,6 +82,20 @@ export async function registerRoutes(app: Express): Promise<Server> {
} }
}); });
app.get('/api/articles/:slug/markets', async (req, res) => {
try {
const article = await storage.getArticleBySlug(req.params.slug);
if (!article) {
return res.status(404).json({ message: "Article not found" });
}
const markets = await storage.getPredictionMarkets(article.id);
res.json(markets);
} catch (error) {
console.error("Error fetching prediction markets for article:", error);
res.status(500).json({ message: "Failed to fetch prediction markets" });
}
});
app.get('/api/articles/featured', async (req, res) => { app.get('/api/articles/featured', async (req, res) => {
try { try {
const limit = parseInt(req.query.limit as string) || 10; const limit = parseInt(req.query.limit as string) || 10;
@ -123,9 +151,26 @@ export async function registerRoutes(app: Express): Promise<Server> {
} }
}); });
app.get('/api/media-outlets/:slug/auction', async (req, res) => {
try {
const outlet = await storage.getMediaOutletBySlug(req.params.slug);
if (!outlet) {
return res.status(404).json({ message: "Media outlet not found" });
}
const auction = await storage.getAuctionByMediaOutlet(outlet.id);
if (!auction) {
return res.status(404).json({ message: "No active auction found for this media outlet" });
}
res.json(auction);
} catch (error) {
console.error("Error fetching auction:", error);
res.status(500).json({ message: "Failed to fetch auction" });
}
});
app.post('/api/auctions/:id/bid', isAuthenticated, async (req: any, res) => { app.post('/api/auctions/:id/bid', isAuthenticated, async (req: any, res) => {
try { try {
const userId = req.user.claims.sub; const userId = req.user.id;
const bidData = insertBidSchema.parse({ const bidData = insertBidSchema.parse({
...req.body, ...req.body,
auctionId: req.params.id, auctionId: req.params.id,
@ -140,6 +185,33 @@ export async function registerRoutes(app: Express): Promise<Server> {
} }
}); });
app.post('/api/media-outlets/:slug/auction/bids', isAuthenticated, async (req: any, res) => {
try {
const outlet = await storage.getMediaOutletBySlug(req.params.slug);
if (!outlet) {
return res.status(404).json({ message: "Media outlet not found" });
}
const auction = await storage.getAuctionByMediaOutlet(outlet.id);
if (!auction) {
return res.status(404).json({ message: "No active auction found for this media outlet" });
}
const userId = req.user.id;
const bidData = insertBidSchema.parse({
...req.body,
auctionId: auction.id,
bidderId: userId
});
const bid = await storage.placeBid(bidData);
res.status(201).json(bid);
} catch (error) {
console.error("Error placing bid:", error);
res.status(500).json({ message: "Failed to place bid" });
}
});
// Media outlet request routes // Media outlet request routes
app.get('/api/media-outlet-requests', isAuthenticated, async (req: any, res) => { app.get('/api/media-outlet-requests', isAuthenticated, async (req: any, res) => {
try { try {

View File

@ -205,6 +205,30 @@ export class DatabaseStorage implements IStorage {
} }
async placeBid(bid: InsertBid): Promise<Bid> { async placeBid(bid: InsertBid): Promise<Bid> {
// First, get the auction to validate
const auction = await this.getAuctionById(bid.auctionId);
if (!auction) {
throw new Error("Auction not found");
}
// Validate auction status
if (!auction.isActive) {
throw new Error("Auction is not active");
}
// Validate auction end date
if (new Date() > auction.endDate) {
throw new Error("Auction has ended");
}
// Validate bid amount
const currentBidAmount = parseFloat(auction.currentBid || "0");
const bidAmount = parseFloat(bid.amount.toString());
if (bidAmount <= currentBidAmount) {
throw new Error(`Bid amount must be higher than current bid of ${currentBidAmount}`);
}
const [newBid] = await db.insert(bids).values(bid).returning(); const [newBid] = await db.insert(bids).values(bid).returning();
// Update auction with highest bid // Update auction with highest bid