diff --git a/src/controllers/bountyController.ts b/src/controllers/bountyController.ts new file mode 100644 index 00000000..1138e943 --- /dev/null +++ b/src/controllers/bountyController.ts @@ -0,0 +1,36 @@ +import { Request, Response } from 'express'; +import Bounty from '../models/Bounty'; +import Submission from '../models/Submission'; + +export const createBounty = async (req: Request, res: Response) => { + try { + const bounty = new Bounty({ ...req.body, postedBy: req.user.id }); + await bounty.save(); + res.status(201).json(bounty); + } catch (error: any) { + res.status(400).json({ error: error.message }); + } +}; + +export const getBounties = async (req: Request, res: Response) => { + try { + const bounties = await Bounty.find({ status: 'open' }); + res.json(bounties); + } catch (error: any) { + res.status(500).json({ error: error.message }); + } +}; + +export const submitProposal = async (req: Request, res: Response) => { + try { + const submission = new Submission({ + bountyId: req.params.id, + submittedBy: req.user.id, + ...req.body + }); + await submission.save(); + res.status(201).json(submission); + } catch (error: any) { + res.status(400).json({ error: error.message }); + } +}; diff --git a/src/models/Bounty.ts b/src/models/Bounty.ts new file mode 100644 index 00000000..da168c25 --- /dev/null +++ b/src/models/Bounty.ts @@ -0,0 +1,33 @@ +import { Schema, model, Document } from 'mongoose'; + +export interface IBounty extends Document { + title: string; + description: string; + scientificContext: string; + deliverables: string[]; + evaluationCriteria: string; + timeline: Date; + prizeAmount: number; + payoutSchedule: string; + isPublic: boolean; + status: 'open' | 'in_review' | 'completed' | 'cancelled'; + postedBy: Schema.Types.ObjectId; + createdAt: Date; + updatedAt: Date; +} + +const bountySchema = new Schema({ + title: { type: String, required: true }, + description: { type: String, required: true }, + scientificContext: { type: String, required: true }, + deliverables: [{ type: String }], + evaluationCriteria: { type: String, required: true }, + timeline: { type: Date, required: true }, + prizeAmount: { type: Number, required: true }, + payoutSchedule: { type: String, required: true }, + isPublic: { type: Boolean, default: true }, + status: { type: String, enum: ['open', 'in_review', 'completed', 'cancelled'], default: 'open' }, + postedBy: { type: Schema.Types.ObjectId, ref: 'User', required: true } +}, { timestamps: true }); + +export default model('Bounty', bountySchema); diff --git a/src/models/Submission.ts b/src/models/Submission.ts new file mode 100644 index 00000000..6affc610 --- /dev/null +++ b/src/models/Submission.ts @@ -0,0 +1,23 @@ +import { Schema, model, Document } from 'mongoose'; + +export interface ISubmission extends Document { + bountyId: Schema.Types.ObjectId; + submittedBy: Schema.Types.ObjectId; + proposal: string; + deliverablesManifest: string[]; + status: 'submitted' | 'under_review' | 'accepted' | 'rejected'; + isAnonymous: boolean; + createdAt: Date; + updatedAt: Date; +} + +const submissionSchema = new Schema({ + bountyId: { type: Schema.Types.ObjectId, ref: 'Bounty', required: true }, + submittedBy: { type: Schema.Types.ObjectId, ref: 'User', required: true }, + proposal: { type: String, required: true }, + deliverablesManifest: [{ type: String }], + status: { type: String, enum: ['submitted', 'under_review', 'accepted', 'rejected'], default: 'submitted' }, + isAnonymous: { type: Boolean, default: false } +}, { timestamps: true }); + +export default model('Submission', submissionSchema); diff --git a/src/routes/bountyRoutes.ts b/src/routes/bountyRoutes.ts new file mode 100644 index 00000000..354cd8ae --- /dev/null +++ b/src/routes/bountyRoutes.ts @@ -0,0 +1,11 @@ +import { Router } from 'express'; +import { createBounty, getBounties, submitProposal } from '../controllers/bountyController'; +import { authenticate } from '../middleware/auth'; + +const router = Router(); + +router.post('/', authenticate, createBounty); +router.get('/', getBounties); +router.post('/:id/submit', authenticate, submitProposal); + +export default router;