mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-18 07:07:35 +01:00
add baseModel plugin with some tests
This commit is contained in:
59
test/api/v3/unit/libs/baseModel.test.js
Normal file
59
test/api/v3/unit/libs/baseModel.test.js
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import baseModel from '../../../../../website/src/libs/api-v3/baseModel';
|
||||||
|
|
||||||
|
describe('Base model plugin', () => {
|
||||||
|
let schema = {
|
||||||
|
add () {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
statics: {},
|
||||||
|
options: {},
|
||||||
|
pre () {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
sandbox.stub(schema, 'add');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('adds a _id field to the schema', () => {
|
||||||
|
baseModel(schema);
|
||||||
|
|
||||||
|
expect(schema.add).to.be.calledWith(sinon.match({
|
||||||
|
_id: sinon.match.object,
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can add timestamps fields', () => {
|
||||||
|
baseModel(schema, {timestamps: true});
|
||||||
|
|
||||||
|
expect(schema.add).to.be.calledTwice;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can sanitize input objects', () => {
|
||||||
|
baseModel(schema, {
|
||||||
|
noSet: ['noUpdateForMe']
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(schema.statics.sanitize).to.exist;
|
||||||
|
let sanitized = schema.statics.sanitize({ok: true, noUpdateForMe: true});
|
||||||
|
|
||||||
|
expect(sanitized).to.have.property('ok');
|
||||||
|
expect(sanitized).to.have.property('noUpdateForMe');
|
||||||
|
expect(sanitized.noUpdateForMe).to.equal(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can make fields private', () => {
|
||||||
|
baseModel(schema, {
|
||||||
|
private: ['amPrivate']
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(schema.options.toObject.transform).to.exist;
|
||||||
|
let objToTransform = {ok: true, amPrivate: true};
|
||||||
|
let privatized = schema.options.toObject.transform({}, objToTransform);
|
||||||
|
|
||||||
|
expect(objToTransform).to.have.property('ok');
|
||||||
|
expect(objToTransform).to.have.property('amPrivate');
|
||||||
|
expect(objToTransform.amPrivate).to.equal(undefined);
|
||||||
|
});
|
||||||
|
});
|
||||||
53
website/src/libs/api-v3/baseModel.js
Normal file
53
website/src/libs/api-v3/baseModel.js
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
import { uuid } from '../../../../common';
|
||||||
|
import validator from 'validator';
|
||||||
|
|
||||||
|
export default function baseModel (schema, options = {}) {
|
||||||
|
schema.add({
|
||||||
|
_id: {
|
||||||
|
type: String,
|
||||||
|
default: uuid.v4,
|
||||||
|
validate: [validator.isUUID, 'Invalid uuid.'], // TODO check for UUID version
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (options.timestamps) {
|
||||||
|
schema.add({
|
||||||
|
createdAt: {
|
||||||
|
type: Date,
|
||||||
|
default: Date.now,
|
||||||
|
},
|
||||||
|
updatedAt: {
|
||||||
|
type: Date,
|
||||||
|
default: Date.now,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.timestamps) {
|
||||||
|
schema.pre('save', function updateUpdatedAt (next) {
|
||||||
|
if (!this.isNew) this.updatedAt = Date.now();
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let noSetFields = ['createdAt', 'updatedAt'];
|
||||||
|
let privateFields = ['__v'];
|
||||||
|
|
||||||
|
if (Array.isArray(options.noSet)) noSetFields.push(...options.noSet);
|
||||||
|
schema.statics.sanitize = function sanitize (objToSanitize = {}) {
|
||||||
|
noSetFields.forEach((fieldPath) => {
|
||||||
|
_.set(objToSanitize, fieldPath, undefined); // TODO decide wheter to use delete here
|
||||||
|
});
|
||||||
|
|
||||||
|
return objToSanitize;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Array.isArray(options.private)) privateFields.push(...options.private);
|
||||||
|
if (!schema.options.toObject) schema.options.toObject = {};
|
||||||
|
schema.options.toObject.transform = function transformToObject (doc, plainObj) {
|
||||||
|
privateFields.forEach((fieldPath) => {
|
||||||
|
_.set(plainObj, fieldPath, undefined); // TODO decide wheter to use delete here
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -5,19 +5,13 @@ import _ from 'lodash';
|
|||||||
import validator from 'validator';
|
import validator from 'validator';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import TaskSchemas from './task';
|
import TaskSchemas from './task';
|
||||||
|
import baseModel from '../libs/api-v3/baseModel';
|
||||||
// import {model as Challenge} from './challenge';
|
// import {model as Challenge} from './challenge';
|
||||||
|
|
||||||
let Schema = mongoose.Schema;
|
let Schema = mongoose.Schema;
|
||||||
|
|
||||||
// User schema definition
|
// User schema definition
|
||||||
export let schema = new Schema({
|
export let schema = new Schema({
|
||||||
// The user _id, stored as a string
|
|
||||||
// TODO validation
|
|
||||||
_id: {
|
|
||||||
type: String,
|
|
||||||
default: shared.uuid,
|
|
||||||
},
|
|
||||||
// TODO validation
|
|
||||||
apiToken: {
|
apiToken: {
|
||||||
type: String,
|
type: String,
|
||||||
default: shared.uuid,
|
default: shared.uuid,
|
||||||
@@ -480,6 +474,12 @@ export let schema = new Schema({
|
|||||||
minimize: false, // So empty objects are returned
|
minimize: false, // So empty objects are returned
|
||||||
});
|
});
|
||||||
|
|
||||||
|
schema.plugin(baseModel, {
|
||||||
|
noSet: ['_id', 'apikey', 'auth.blocked', 'auth.timestamps', 'lastCron', 'auth.local.hashed_password', 'auth.local.salt'],
|
||||||
|
private: ['auth.local.hashed_password', 'auth.local.salt'],
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
schema.methods.deleteTask = function deleteTask (tid) {
|
schema.methods.deleteTask = function deleteTask (tid) {
|
||||||
this.ops.deleteTask({params: {id: tid}}, () => {}); // TODO remove this whole method, since it just proxies, and change all references to this method
|
this.ops.deleteTask({params: {id: tid}}, () => {}); // TODO remove this whole method, since it just proxies, and change all references to this method
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user