From cef5a5fabfeed1dc3356e736fd1869c174600b0d Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Tue, 9 Feb 2016 11:26:46 -0800 Subject: [PATCH] First part of schemas PUT --- spec/schemas.spec.js | 99 +++++++++++++++++++++++++++++++++++++++++++- src/schemas.js | 69 +++++++++++++++++++++--------- 2 files changed, 148 insertions(+), 20 deletions(-) diff --git a/spec/schemas.spec.js b/spec/schemas.spec.js index 68ac31c9..907c5f65 100644 --- a/spec/schemas.spec.js +++ b/spec/schemas.spec.js @@ -94,7 +94,7 @@ describe('schemas', () => { headers: restKeyHeaders, }, (error, response, body) => { expect(response.statusCode).toEqual(401); - expect(body.error).toEqual('unauthorized'); + expect(body.error).toEqual('master key not specified'); done(); }); }); @@ -318,4 +318,101 @@ describe('schemas', () => { done(); }); }); + + it('requires the master key to modify schemas', done => { + request.post({ + url: 'http://localhost:8378/1/schemas/NewClass', + headers: masterKeyHeaders, + json: true, + body: {}, + }, (error, response, body) => { + request.put({ + url: 'http://localhost:8378/1/schemas/NewClass', + headers: noAuthHeaders, + json: true, + body: {}, + }, (error, response, body) => { + expect(response.statusCode).toEqual(403); + expect(body.error).toEqual('unauthorized'); + done(); + }); + }); + }); + + it('rejects class name mis-matches', done => { + request.put({ + url: 'http://localhost:8378/1/schemas/NewClass', + headers: masterKeyHeaders, + json: true, + body: {className: 'WrongClassName'} + }, (error, response, body) => { + expect(response.statusCode).toEqual(400); + expect(body.code).toEqual(Parse.Error.INVALID_CLASS_NAME); + expect(body.error).toEqual('class name mismatch between WrongClassName and NewClass'); + }); + }); + + it('refuses to add fields to non-existent classes', done => { + request.put({ + url: 'http://localhost:8378/1/schemas/NoClass', + headers: masterKeyHeaders, + json: true, + body: { + fields: { + newField: {type: 'String'} + } + } + }, (error, response, body) => { + expect(response.statusCode).toEqual(400); + expect(body.code).toEqual(Parse.Error.INVALID_CLASS_NAME); + expect(body.error).toEqual('class NoClass does not exist'); + done(); + }); + }); + + it('put with no modifications returns all fields', done => { + var obj = hasAllPODobject(); + obj.save() + .then(() => { + request.put({ + url: 'http://localhost:8378/1/schemas/HasAllPOD' + headers: masterKeyHeaders, + json: true, + body: {}, + }, (error, response, body) => { + expect(body).toEqual(plainOldDataSchema); + done(); + }); + }); + }); + + it('lets you add fields', done => { + request.post({ + url: 'http://localhost:8378/1/schemas/NewClass', + headers: masterKeyHeaders, + json: true, + body: {}, + }, (error, response, body) => { + request.put({ + url: 'http://localhost:8378/1/schemas/NewClass', + headers: masterKeyHeaders, + json: true, + body: { + fields: { + newField: {type: 'String'} + } + } + }, (error, response, body) => { + expect(body).toEqual('blah'); + request.get({ + url: 'http://localhost:8378/1/schemas/NewClass', + headers: masterKeyHeaders, + json: true, + }, (error, response, body) => { + expect(body).toEqual('blah'); + done(); + }); + }); + }) + }); }); diff --git a/src/schemas.js b/src/schemas.js index 837224ab..c17e9407 100644 --- a/src/schemas.js +++ b/src/schemas.js @@ -7,6 +7,23 @@ var express = require('express'), var router = new PromiseRouter(); +function masterKeyRequiredResponse() { + return Promise.resolve({ + status: 401, + response: {error: 'master key not specified'}, + }) +} + +function classNameMismatchResponse(bodyClass, pathClass) { + return Promise.resolve({ + status: 400, + response: { + code: Parse.Error.INVALID_CLASS_NAME, + error: 'class name mismatch between ' + bodyClass + ' and ' + pathClass, + } + }); +} + function mongoFieldTypeToSchemaAPIType(type) { if (type[0] === '*') { return { @@ -55,10 +72,7 @@ function mongoSchemaToSchemaAPIResponse(schema) { function getAllSchemas(req) { if (!req.auth.isMaster) { - return Promise.resolve({ - status: 401, - response: {error: 'master key not specified'}, - }); + return masterKeyRequiredResponse(); } return req.config.database.collection('_SCHEMA') .then(coll => coll.find({}).toArray()) @@ -69,10 +83,7 @@ function getAllSchemas(req) { function getOneSchema(req) { if (!req.auth.isMaster) { - return Promise.resolve({ - status: 401, - response: {error: 'unauthorized'}, - }); + return masterKeyRequiredResponse(); } return req.config.database.collection('_SCHEMA') .then(coll => coll.findOne({'_id': req.params.className})) @@ -88,20 +99,11 @@ function getOneSchema(req) { function createSchema(req) { if (!req.auth.isMaster) { - return Promise.resolve({ - status: 401, - response: {error: 'master key not specified'}, - }); + return masterKeyRequiredResponse(); } if (req.params.className && req.body.className) { if (req.params.className != req.body.className) { - return Promise.resolve({ - status: 400, - response: { - code: Parse.Error.INVALID_CLASS_NAME, - error: 'class name mismatch between ' + req.body.className + ' and ' + req.params.className, - }, - }); + return classNameMismatchResponse(req.body.className, req.params.className); } } var className = req.params.className || req.body.className; @@ -123,9 +125,38 @@ function createSchema(req) { })); } +function modifySchema(req) { + if (!req.auth.isMaster) { + return masterKeyRequiredResponse(); + } + + if (req.body.className && req.body.className != req.params.className) { + return classNameMismatchResponse(req.body.className, req.path.className); + } + + if (!req.body.fields) { + req.body.fields = {}; + } + + return req.config.database.loadSchema() + .then(schema => schema.hasClass(req.params.className)) + .then(hasClass => { + if (!hasClass) { + return Promise.resolve({ + status: 400, + response: { + code: Parse.Error.INVALID_CLASS_NAME, + error: 'class ' + req.params.className + ' does not exist', + } + }); + } + }); +} + router.route('GET', '/schemas', getAllSchemas); router.route('GET', '/schemas/:className', getOneSchema); router.route('POST', '/schemas', createSchema); router.route('POST', '/schemas/:className', createSchema); +router.route('PUT', '/schemas/:className', modifySchema); module.exports = router;