-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Expand file tree
/
Copy pathgetProjectsForUser.js
More file actions
101 lines (83 loc) · 2.89 KB
/
Copy pathgetProjectsForUser.js
File metadata and controls
101 lines (83 loc) · 2.89 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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import Project from '../../models/project';
import { User } from '../../models/user';
import { toApi as toApiProjectObject } from '../../domain-objects/Project';
/**
* Fetches projects for the username in the request.
* Handles errors.
* Returns a success response based on the provided `mapProjectsToResponse` function.
*/
const createCoreHandler = (mapProjectsToResponse) => async (req, res) => {
try {
const { username } = req.params;
const { page, limit, sortField, sortDir, q } = req.query;
if (!username) {
return res.status(422).json({ message: 'Username not provided' });
}
const user = await User.findByUsername(username);
if (!user) {
return res
.status(404)
.json({ message: 'User with that username does not exist.' });
}
const canViewPrivate = req.user && req.user._id.equals(user._id);
const filter = { user: user._id };
if (!canViewPrivate) {
filter.visibility = { $ne: 'Private' };
}
if (q && q.trim()) {
const term = q.trim();
const escaped = term.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
filter.name = { $regex: escaped, $options: 'i' };
}
const usePagination = page !== undefined && limit !== undefined;
const parsedPage = Math.max(parseInt(page, 10) || 1, 1);
const parsedLimit = Math.min(Math.max(parseInt(limit, 10) || 10, 1), 100);
const dir = sortDir === 'desc' ? -1 : 1;
const allowedSortFields = new Set([
'name',
'createdAt',
'updatedAt',
'visibility'
]);
const safeSortField = allowedSortFields.has(sortField)
? sortField
: 'updatedAt';
const query = Project.find(filter)
.sort({ [safeSortField]: dir, _id: dir })
.select('name files id createdAt updatedAt visibility');
if (usePagination) {
query.skip((parsedPage - 1) * parsedLimit).limit(parsedLimit);
}
const projects = await query.exec();
const totalProjects = usePagination
? await Project.countDocuments(filter)
: projects.length;
const response = {
projects: mapProjectsToResponse(projects),
...(usePagination && {
metadata: {
page: parsedPage,
totalPages: Math.max(Math.ceil(totalProjects / parsedLimit), 1),
totalProjects,
limit: parsedLimit,
hasPagination: true
}
})
};
return res.json(response);
} catch (error) {
return res.status(500).json({ message: 'Error fetching projects' });
}
};
/**
* Main handler returns an array of project objects.
*/
const getProjectsForUser = createCoreHandler((projects) => projects);
export default getProjectsForUser;
/**
* Handler for the public API returns an object with property `sketches`.
* The array of sketches contains the `id` and `name` only.
*/
export const apiGetProjectsForUser = createCoreHandler((projects) => ({
sketches: projects.map((p) => toApiProjectObject(p))
}));