Skip to content

Commit ca7cec8

Browse files
committed
Initial Commit
1 parent 82cd275 commit ca7cec8

File tree

4 files changed

+125
-0
lines changed

4 files changed

+125
-0
lines changed

spec/CloudCode.spec.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,62 @@ describe('Cloud Code', () => {
3838
});
3939
});
4040
});
41+
const masterKeyHeaders = {
42+
'X-Parse-Application-Id': 'test',
43+
'X-Parse-Rest-API-Key': 'rest',
44+
'X-Parse-Master-Key': 'test',
45+
'Content-Type': 'application/json',
46+
};
47+
const masterKeyOptions = {
48+
headers: masterKeyHeaders,
49+
json: true,
50+
};
51+
it('can load cloud code file from dashboard', async done => {
52+
const cloudDir = './spec/cloud/cloudCodeAbsoluteFile.js';
53+
await reconfigureServer({ cloud: cloudDir });
54+
const options = Object.assign({}, masterKeyOptions, {
55+
method: 'GET',
56+
url: Parse.serverURL + '/releases/latest',
57+
});
58+
request(options)
59+
.then(res => {
60+
expect(Array.isArray(res.data)).toBe(true);
61+
const first = res.data[0];
62+
expect(first.userFiles).toBeDefined();
63+
expect(first.checksums).toBeDefined();
64+
expect(first.userFiles).toContain(cloudDir);
65+
expect(first.checksums).toContain(cloudDir);
66+
options.url = Parse.serverURL + '/scripts/spec/cloud/cloudCodeAbsoluteFile.js';
67+
return request(options);
68+
})
69+
.then(res => {
70+
const response = res.data;
71+
expect(response).toContain('It is possible to define cloud code in a file.');
72+
done();
73+
});
74+
});
75+
76+
it('can load multiple cloud code files from dashboard', async done => {
77+
const cloudDir = './spec/cloud/cloudCodeRequireFiles.js';
78+
await reconfigureServer({ cloud: cloudDir });
79+
const options = Object.assign({}, masterKeyOptions, {
80+
method: 'GET',
81+
url: Parse.serverURL + '/releases/latest',
82+
});
83+
request(options).then(res => {
84+
expect(Array.isArray(res.data)).toBe(true);
85+
const first = res.data[0];
86+
expect(first.userFiles).toBeDefined();
87+
expect(first.checksums).toBeDefined();
88+
expect(first.userFiles).toContain(cloudDir);
89+
expect(first.checksums).toContain(cloudDir);
90+
expect(first.userFiles).toContain('spec/cloud/cloudCodeAbsoluteFile.js');
91+
expect(first.checksums).toContain('spec/cloud/cloudCodeAbsoluteFile.js');
92+
expect(first.userFiles).toContain('spec/cloud/cloudCodeRelativeFile.js');
93+
expect(first.checksums).toContain('spec/cloud/cloudCodeRelativeFile.js');
94+
done();
95+
});
96+
});
4197

4298
it('can create functions', done => {
4399
Parse.Cloud.define('hello', () => {

spec/cloud/cloudCodeRequireFiles.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
require('./cloudCodeAbsoluteFile.js');
2+
require('./cloudCodeRelativeFile.js');

src/Routers/CloudCodeRouter.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import Parse from 'parse/node';
33
import rest from '../rest';
44
const triggers = require('../triggers');
55
const middleware = require('../middlewares');
6+
const fs = require('fs');
7+
const path = require('path');
68

79
function formatJobSchedule(job_schedule) {
810
if (typeof job_schedule.startAfter === 'undefined') {
@@ -53,6 +55,18 @@ export class CloudCodeRouter extends PromiseRouter {
5355
middleware.promiseEnforceMasterKeyAccess,
5456
CloudCodeRouter.deleteJob
5557
);
58+
this.route(
59+
'GET',
60+
'/releases/latest',
61+
middleware.promiseEnforceMasterKeyAccess,
62+
CloudCodeRouter.getCloudCode
63+
);
64+
this.route(
65+
'GET',
66+
'/scripts/*',
67+
middleware.promiseEnforceMasterKeyAccess,
68+
CloudCodeRouter.getCloudFile
69+
);
5670
}
5771

5872
static getJobs(req) {
@@ -120,4 +134,56 @@ export class CloudCodeRouter extends PromiseRouter {
120134
};
121135
});
122136
}
137+
static getCloudFile(req) {
138+
const file = req.url.replace('/scripts', '');
139+
const dirName = __dirname.split('lib')[0];
140+
const filePath = path.join(dirName, file);
141+
if (!fs.existsSync(filePath) || !fs.lstatSync(filePath).isFile()) {
142+
throw new Parse.Error(Parse.Error.INTERNAL_SERVER_ERROR, 'Invalid file url.');
143+
}
144+
return {
145+
response: fs.readFileSync(filePath, 'utf8'),
146+
};
147+
}
148+
static getCloudCode(req) {
149+
const config = req.config;
150+
const dirName = __dirname.split('node_modules')[0];
151+
const cloudLocation = ('' + config.cloud).replace(dirName, '');
152+
const cloudFiles = [];
153+
const getRequiredFromFile = (file, directory) => {
154+
try {
155+
const fileData = fs.readFileSync(file, 'utf8');
156+
const requireStatements = fileData.split('require(');
157+
for (let reqStatement of requireStatements) {
158+
reqStatement = reqStatement.split(')')[0].slice(1, -1);
159+
const filePath = path.join(directory, reqStatement);
160+
if (!fs.existsSync(filePath) || !fs.lstatSync(filePath).isFile()) {
161+
continue;
162+
}
163+
const requireData = fs.readFileSync(filePath, 'utf8');
164+
const newFilePath = filePath.replace(dirName, '');
165+
cloudFiles.push(newFilePath);
166+
if (requireData.includes('require(')) {
167+
getRequiredFromFile(newFilePath, path.dirname(filePath));
168+
}
169+
}
170+
} catch (e) {
171+
/* */
172+
}
173+
};
174+
cloudFiles.push(cloudLocation);
175+
getRequiredFromFile(cloudLocation, path.dirname(config.cloud));
176+
const response = {};
177+
for (const file of cloudFiles) {
178+
response[file] = new Date();
179+
}
180+
return {
181+
response: [
182+
{
183+
checksums: JSON.stringify({ cloud: response }),
184+
userFiles: JSON.stringify({ cloud: response }),
185+
},
186+
],
187+
};
188+
}
123189
}

src/Routers/FeaturesRouter.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export class FeaturesRouter extends PromiseRouter {
2121
},
2222
cloudCode: {
2323
jobs: true,
24+
viewCode: true,
2425
},
2526
logs: {
2627
level: true,

0 commit comments

Comments
 (0)