-
Notifications
You must be signed in to change notification settings - Fork 210
Expand file tree
/
Copy pathlive.ts
More file actions
85 lines (77 loc) · 2.8 KB
/
Copy pathlive.ts
File metadata and controls
85 lines (77 loc) · 2.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import type { NextApiResponse } from 'next';
import logger from '@/lib/logger';
import { prisma } from '@/prisma';
import { type EnumBountyTypeFilter } from '@/prisma/commonInputTypes';
import { type BountyType } from '@/prisma/enums';
import { type BountiesFindManyArgs } from '@/prisma/models/Bounties';
import { parseBoundedIntegerParam } from '@/utils/apiPagination';
import { type NextApiRequestWithAgent } from '@/features/auth/types';
import { withAgentAuth } from '@/features/auth/utils/withAgentAuth';
import { listingSelect } from '@/features/listings/constants/schema';
/**
* GET /api/agents/listings/live
* Discovery endpoint returning currently active and agent-accessible listings.
* Filters for status OPEN, agentAccess in ['AGENT_ALLOWED', 'AGENT_ONLY'], and deadline >= now.
*/
async function handler(req: NextApiRequestWithAgent, res: NextApiResponse) {
const params = req.query;
const type = params.type as EnumBountyTypeFilter | BountyType | undefined;
const takeResult = parseBoundedIntegerParam(params.take, {
defaultValue: 10,
maxValue: 50,
name: 'take',
});
if (!takeResult.ok) {
return res.status(400).json({ error: takeResult.error });
}
let deadlineDate: Date | undefined = new Date();
if (params.deadline !== undefined) {
if (typeof params.deadline !== 'string' || params.deadline.trim() === '') {
return res.status(400).json({ error: 'Expected ISO-8601 datetime format for deadline' });
}
const rawDeadline = params.deadline.trim();
const parsed = new Date(rawDeadline);
if (isNaN(parsed.getTime())) {
return res.status(400).json({ error: 'Expected ISO-8601 datetime format for deadline' });
}
deadlineDate = parsed;
}
const exclusiveSponsorId = params.exclusiveSponsorId as string | undefined;
let excludeIds = params['excludeIds[]'];
if (typeof excludeIds === 'string') {
excludeIds = [excludeIds];
}
const listingQueryOptions: BountiesFindManyArgs = {
where: {
id: {
notIn: excludeIds,
},
isPublished: true,
isActive: true,
isPrivate: false,
isArchived: false,
status: 'OPEN',
deadline: deadlineDate ? { gte: deadlineDate } : undefined,
type: type || { in: ['bounty', 'project', 'hackathon'] },
agentAccess: { in: ['AGENT_ALLOWED', 'AGENT_ONLY'] },
sponsor: {
isVerified: true,
},
sponsorId: exclusiveSponsorId,
},
select: listingSelect,
take,
orderBy: [{ deadline: 'asc' }, { winnersAnnouncedAt: 'desc' }],
};
try {
const listings = await prisma.bounties.findMany(listingQueryOptions);
res.status(200).json(listings);
} catch (error) {
logger.error(error);
res.status(400).json({
error,
message: 'Error occurred while fetching listings',
});
}
}
export default withAgentAuth(handler);