Skip to content

Commit 6982e47

Browse files
authored
Merge branch 'develop' into refactor/AddToCollectionSketchList
2 parents e189ad2 + 1e218f4 commit 6982e47

File tree

15 files changed

+297
-307
lines changed

15 files changed

+297
-307
lines changed

client/modules/IDE/components/About.jsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ function About(props) {
2828
/>
2929
<div className="about__content-column">
3030
<p className="about__version-info">
31-
Web Editor: <span>v{packageData?.version}</span>
31+
{t('About.WebEditor')}: <span>v{packageData?.version}</span>
3232
</p>
3333
<p className="about__version-info">
3434
p5.js: <span>v{p5version}</span>
@@ -44,7 +44,7 @@ function About(props) {
4444
aria-hidden="true"
4545
focusable="false"
4646
/>
47-
Home
47+
{t('About.Home')}
4848
</a>
4949
</p>
5050
<p className="about__content-column-list">
@@ -86,7 +86,7 @@ function About(props) {
8686
aria-hidden="true"
8787
focusable="false"
8888
/>
89-
Twitter
89+
{t('About.Twitter')}
9090
</a>
9191
</p>
9292
<p className="about__content-column-list">
@@ -100,7 +100,7 @@ function About(props) {
100100
aria-hidden="true"
101101
focusable="false"
102102
/>
103-
Instagram
103+
{t('About.Instagram')}
104104
</a>
105105
</p>
106106
</div>
@@ -159,7 +159,7 @@ function About(props) {
159159
aria-hidden="true"
160160
focusable="false"
161161
/>
162-
Discord
162+
{t('About.Discord')}
163163
</a>
164164
</p>
165165
<p className="about__content-column-list">
Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,17 @@
11
import Collection from '../../models/collection';
22
import User from '../../models/user';
33

4-
export default function collectionForUserExists(
5-
username,
6-
collectionId,
7-
callback
8-
) {
9-
function sendFailure() {
10-
callback(false);
11-
}
12-
13-
function sendSuccess(collection) {
14-
callback(collection != null);
15-
}
16-
17-
function findUser() {
18-
return User.findByUsername(username);
19-
}
20-
21-
function findCollection(owner) {
22-
if (owner == null) {
23-
throw new Error('User not found');
24-
}
25-
26-
return Collection.findOne({ _id: collectionId, owner });
27-
}
28-
29-
return findUser().then(findCollection).then(sendSuccess).catch(sendFailure);
4+
/**
5+
* @param {string} username
6+
* @param {string} collectionId
7+
* @return {Promise<boolean>}
8+
*/
9+
export default async function collectionForUserExists(username, collectionId) {
10+
const user = await User.findByUsername(username);
11+
if (!user) return false;
12+
const collection = await Collection.findOne({
13+
_id: collectionId,
14+
owner: user
15+
}).exec();
16+
return collection != null;
3017
}

server/controllers/project.controller.js

Lines changed: 37 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -169,29 +169,28 @@ export function getProjects(req, res) {
169169
}
170170
}
171171

172-
export function projectExists(projectId, callback) {
173-
Project.findById(projectId, (err, project) =>
174-
project ? callback(true) : callback(false)
175-
);
172+
/**
173+
* @param {string} projectId
174+
* @return {Promise<boolean>}
175+
*/
176+
export async function projectExists(projectId) {
177+
const project = await Project.findById(projectId);
178+
return project != null;
176179
}
177180

178-
export function projectForUserExists(username, projectId, callback) {
179-
User.findByUsername(username, (err, user) => {
180-
if (!user) {
181-
callback(false);
182-
return;
183-
}
184-
Project.findOne(
185-
{ user: user._id, $or: [{ _id: projectId }, { slug: projectId }] },
186-
(innerErr, project) => {
187-
if (!project) {
188-
callback(false);
189-
return;
190-
}
191-
callback(true);
192-
}
193-
);
181+
/**
182+
* @param {string} username
183+
* @param {string} projectId
184+
* @return {Promise<boolean>}
185+
*/
186+
export async function projectForUserExists(username, projectId) {
187+
const user = await User.findByUsername(username);
188+
if (!user) return false;
189+
const project = await Project.findOne({
190+
user: user._id,
191+
$or: [{ _id: projectId }, { slug: projectId }]
194192
});
193+
return project != null;
195194
}
196195

197196
function bundleExternalLibs(project) {
@@ -215,48 +214,27 @@ function bundleExternalLibs(project) {
215214
});
216215
}
217216

218-
function addFileToZip(file, files, zip, path = '') {
219-
return new Promise((resolve, reject) => {
220-
if (file.fileType === 'folder') {
221-
const newPath = file.name === 'root' ? path : `${path}${file.name}/`;
222-
const numChildFiles = file.children.filter((f) => f.fileType !== 'folder')
223-
.length;
224-
let childrenAdded = 0;
225-
if (numChildFiles === 0) {
226-
zip.folder(file.name);
227-
resolve();
228-
}
229-
file.children.forEach(async (fileId) => {
217+
async function addFileToZip(file, files, zip) {
218+
if (file.fileType === 'folder') {
219+
const folderZip = file.name === 'root' ? zip : zip.folder(file.name);
220+
await Promise.all(
221+
file.children.map((fileId) => {
230222
const childFile = files.find((f) => f.id === fileId);
231-
232-
try {
233-
await addFileToZip(childFile, files, zip, newPath);
234-
childrenAdded += 1;
235-
236-
if (childrenAdded === numChildFiles) {
237-
resolve();
238-
}
239-
} catch (err) {
240-
reject(err);
241-
}
223+
return addFileToZip(childFile, files, folderZip);
224+
})
225+
);
226+
} else if (file.url) {
227+
try {
228+
const res = await axios.get(file.url, {
229+
responseType: 'arraybuffer'
242230
});
243-
} else if (file.url) {
244-
axios
245-
.get(file.url, {
246-
responseType: 'arraybuffer'
247-
})
248-
.then(({ data }) => {
249-
zip.file(`${path}${file.name}`, data);
250-
resolve();
251-
})
252-
.catch((err) => {
253-
reject(err);
254-
});
255-
} else {
256-
zip.file(`${path}${file.name}`, file.content);
257-
resolve();
231+
zip.file(file.name, res.data);
232+
} catch (e) {
233+
zip.file(file.name, new ArrayBuffer(0));
258234
}
259-
});
235+
} else {
236+
zip.file(file.name, file.content);
237+
}
260238
}
261239

262240
async function buildZip(project, req, res) {

server/controllers/project.controller/__test__/getProjectsForUser.test.js

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,18 @@ describe('project.controller', () => {
2323
});
2424

2525
describe('getProjectsForUser()', () => {
26-
it('returns empty array user not supplied as parameter', (done) => {
26+
it('returns validation error if username not provided', (done) => {
2727
const request = new Request();
2828
request.setParams({});
2929
const response = new Response();
3030

3131
const promise = getProjectsForUser(request, response);
3232

3333
function expectations() {
34-
expect(response.status).toHaveBeenCalledWith(200);
35-
expect(response.json).toHaveBeenCalledWith([]);
34+
expect(response.status).toHaveBeenCalledWith(422);
35+
expect(response.json).toHaveBeenCalledWith({
36+
message: 'Username not provided'
37+
});
3638

3739
done();
3840
}
@@ -47,7 +49,7 @@ describe('project.controller', () => {
4749

4850
UserMock.expects('findOne')
4951
.withArgs({ username: 'abc123' })
50-
.yields(null, null);
52+
.resolves(null);
5153

5254
const promise = getProjectsForUser(request, response);
5355

@@ -70,15 +72,15 @@ describe('project.controller', () => {
7072

7173
UserMock.expects('findOne')
7274
.withArgs({ username: 'abc123' })
73-
.yields(new Error(), null);
75+
.rejects(new Error());
7476

7577
const promise = getProjectsForUser(request, response);
7678

7779
function expectations() {
78-
expect(response.status).toHaveBeenCalledWith(500);
7980
expect(response.json).toHaveBeenCalledWith({
8081
message: 'Error fetching projects'
8182
});
83+
expect(response.status).toHaveBeenCalledWith(500);
8284

8385
done();
8486
}
@@ -88,7 +90,7 @@ describe('project.controller', () => {
8890
});
8991

9092
describe('apiGetProjectsForUser()', () => {
91-
it('returns validation error if user id not provided', (done) => {
93+
it('returns validation error if username not provided', (done) => {
9294
const request = new Request();
9395
request.setParams({});
9496
const response = new Response();
@@ -114,7 +116,7 @@ describe('project.controller', () => {
114116

115117
UserMock.expects('findOne')
116118
.withArgs({ username: 'abc123' })
117-
.yields(null, null);
119+
.resolves(null);
118120

119121
const promise = apiGetProjectsForUser(request, response);
120122

@@ -137,7 +139,7 @@ describe('project.controller', () => {
137139

138140
UserMock.expects('findOne')
139141
.withArgs({ username: 'abc123' })
140-
.yields(new Error(), null);
142+
.rejects(new Error());
141143

142144
const promise = apiGetProjectsForUser(request, response);
143145

Lines changed: 42 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,47 @@
11
import Project from '../../models/project';
22
import User from '../../models/user';
33
import { toApi as toApiProjectObject } from '../../domain-objects/Project';
4-
import createApplicationErrorClass from '../../utils/createApplicationErrorClass';
54

6-
const UserNotFoundError = createApplicationErrorClass('UserNotFoundError');
7-
8-
function getProjectsForUserName(username) {
9-
return new Promise((resolve, reject) => {
10-
User.findByUsername(username, (err, user) => {
11-
if (err) {
12-
reject(err);
13-
return;
14-
}
15-
16-
if (!user) {
17-
reject(new UserNotFoundError());
18-
return;
19-
}
20-
21-
Project.find({ user: user._id })
22-
.sort('-createdAt')
23-
.select('name files id createdAt updatedAt')
24-
.exec((innerErr, projects) => {
25-
if (innerErr) {
26-
reject(innerErr);
27-
return;
28-
}
29-
30-
resolve(projects);
31-
});
32-
});
33-
});
34-
}
35-
36-
export default function getProjectsForUser(req, res) {
37-
if (req.params.username) {
38-
return getProjectsForUserName(req.params.username)
39-
.then((projects) => res.json(projects))
40-
.catch((err) => {
41-
if (err instanceof UserNotFoundError) {
42-
res
43-
.status(404)
44-
.json({ message: 'User with that username does not exist.' });
45-
} else {
46-
res.status(500).json({ message: 'Error fetching projects' });
47-
}
48-
});
5+
/**
6+
* Fetches projects for the username in the request.
7+
* Handles errors.
8+
* Returns a success response based on the provided `mapProjectsToResponse` function.
9+
*/
10+
const createCoreHandler = (mapProjectsToResponse) => async (req, res) => {
11+
try {
12+
const { username } = req.params;
13+
if (!username) {
14+
res.status(422).json({ message: 'Username not provided' });
15+
return;
16+
}
17+
const user = await User.findByUsername(username);
18+
if (!user) {
19+
res
20+
.status(404)
21+
.json({ message: 'User with that username does not exist.' });
22+
return;
23+
}
24+
const projects = await Project.find({ user: user._id })
25+
.sort('-createdAt')
26+
.select('name files id createdAt updatedAt')
27+
.exec();
28+
const response = mapProjectsToResponse(projects);
29+
res.json(response);
30+
} catch (e) {
31+
res.status(500).json({ message: 'Error fetching projects' });
4932
}
50-
51-
// could just move this to client side
52-
res.status(200).json([]);
53-
return Promise.resolve();
54-
}
55-
56-
export function apiGetProjectsForUser(req, res) {
57-
if (req.params.username) {
58-
return getProjectsForUserName(req.params.username)
59-
.then((projects) => {
60-
const asApiObjects = projects.map((p) => toApiProjectObject(p));
61-
res.json({ sketches: asApiObjects });
62-
})
63-
.catch((err) => {
64-
if (err instanceof UserNotFoundError) {
65-
res
66-
.status(404)
67-
.json({ message: 'User with that username does not exist.' });
68-
} else {
69-
res.status(500).json({ message: 'Error fetching projects' });
70-
}
71-
});
72-
}
73-
74-
res.status(422).json({ message: 'Username not provided' });
75-
return Promise.resolve();
76-
}
33+
};
34+
35+
/**
36+
* Main handler returns an array of project objects.
37+
*/
38+
const getProjectsForUser = createCoreHandler((projects) => projects);
39+
export default getProjectsForUser;
40+
41+
/**
42+
* Handler for the public API returns an object with property `sketches`.
43+
* The array of sketches contains the `id` and `name` only.
44+
*/
45+
export const apiGetProjectsForUser = createCoreHandler((projects) => ({
46+
sketches: projects.map((p) => toApiProjectObject(p))
47+
}));

0 commit comments

Comments
 (0)