diff --git a/server/routes.ts b/server/routes.ts index 9e4f39c..21fe085 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -55,6 +55,20 @@ export async function registerRoutes(app: Express): Promise { } }); + 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) => { try { const article = await storage.getArticleBySlug(req.params.slug); @@ -68,6 +82,20 @@ export async function registerRoutes(app: Express): Promise { } }); + 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) => { try { const limit = parseInt(req.query.limit as string) || 10; @@ -123,9 +151,26 @@ export async function registerRoutes(app: Express): Promise { } }); + 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) => { try { - const userId = req.user.claims.sub; + const userId = req.user.id; const bidData = insertBidSchema.parse({ ...req.body, auctionId: req.params.id, @@ -140,6 +185,33 @@ export async function registerRoutes(app: Express): Promise { } }); + 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 app.get('/api/media-outlet-requests', isAuthenticated, async (req: any, res) => { try { diff --git a/server/storage.ts b/server/storage.ts index 89d6445..8d96152 100644 --- a/server/storage.ts +++ b/server/storage.ts @@ -205,6 +205,30 @@ export class DatabaseStorage implements IStorage { } async placeBid(bid: InsertBid): Promise { + // 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(); // Update auction with highest bid