37fcf46972
* Converts import script to use public API endpoints The endpoints don't exist yet, but this is a good way to see how the implementation of the data structures differ. * Exposes public API endpoint to fetch user's sketches * Implements public API delete endpoint * Adds helper to create custom ApplicationError classes * Adds create project endpoint that understand API's data structure This transforms the nested tree of file data into a mongoose Project model * Returns '201 Created' to match API spec * Removes 'CustomError' variable assignment as it shows up in test output * transformFiles will return file validation errors * Tests API project controller * Tests toModel() * Creates default files if no root-level .html file is provided * Do not auto-generate a slug if it is provided Fixes a bug where the slug was auto-generated using the sketch name, even if a slug property had been provided. * Validates uniqueness of slugs for projects created by the public API * Adds tests for slug uniqueness * Configures node's Promise implementation for mongoose (fixes warnings) * Moves createProject tests to match controller location * Adds support for code to ApplicationErrors * deleteProject controller tests * getProjectsForUser controller tests - implements tests - update apiKey tests to use new User mocks * Ensure error objects have consistent property names `message` is used as a high-level description of the errors `detail` is optional and has an plain language explanation of the individual errors `errors` is an array of each individual problem from `detail` in a machine-readable format * Assert environment variables are provided at script start * Version public API * Expect "files" property to always be provided * Fixes linting error * Converts import script to use public API endpoints The endpoints don't exist yet, but this is a good way to see how the implementation of the data structures differ. * Exposes public API endpoint to fetch user's sketches * Implements public API delete endpoint * Adds helper to create custom ApplicationError classes * Adds create project endpoint that understand API's data structure This transforms the nested tree of file data into a mongoose Project model * Returns '201 Created' to match API spec * Removes 'CustomError' variable assignment as it shows up in test output * transformFiles will return file validation errors * Tests API project controller * Tests toModel() * Creates default files if no root-level .html file is provided * Do not auto-generate a slug if it is provided Fixes a bug where the slug was auto-generated using the sketch name, even if a slug property had been provided. * Validates uniqueness of slugs for projects created by the public API * Adds tests for slug uniqueness * Configures node's Promise implementation for mongoose (fixes warnings) * Moves createProject tests to match controller location * deleteProject controller tests * Adds support for code to ApplicationErrors * getProjectsForUser controller tests - implements tests - update apiKey tests to use new User mocks * Ensure error objects have consistent property names `message` is used as a high-level description of the errors `detail` is optional and has an plain language explanation of the individual errors `errors` is an array of each individual problem from `detail` in a machine-readable format * Assert environment variables are provided at script start * Version public API * Expect "files" property to always be provided * Fixes linting error * Checks that authenticated user has permission to create under this namespace Previously, the project was always created under the authenticated user's namespace, but this not obvious behaviour.
91 lines
2 KiB
JavaScript
91 lines
2 KiB
JavaScript
import mongoose from 'mongoose';
|
|
import shortid from 'shortid';
|
|
import slugify from 'slugify';
|
|
|
|
// Register User model as it's referenced by Project
|
|
import './user';
|
|
|
|
const { Schema } = mongoose;
|
|
|
|
const fileSchema = new Schema(
|
|
{
|
|
name: { type: String, default: 'sketch.js' },
|
|
content: { type: String, default: '' },
|
|
url: { type: String },
|
|
children: { type: [String], default: [] },
|
|
fileType: { type: String, default: 'file' },
|
|
isSelectedFile: { type: Boolean }
|
|
},
|
|
{ timestamps: true, _id: true, usePushEach: true }
|
|
);
|
|
|
|
fileSchema.virtual('id').get(function getFileId() {
|
|
return this._id.toHexString();
|
|
});
|
|
|
|
fileSchema.set('toJSON', {
|
|
virtuals: true
|
|
});
|
|
|
|
const projectSchema = new Schema(
|
|
{
|
|
name: { type: String, default: "Hello p5.js, it's the server" },
|
|
user: { type: Schema.Types.ObjectId, ref: 'User' },
|
|
serveSecure: { type: Boolean, default: false },
|
|
files: { type: [fileSchema] },
|
|
_id: { type: String, default: shortid.generate },
|
|
slug: { type: String }
|
|
},
|
|
{ timestamps: true, usePushEach: true }
|
|
);
|
|
|
|
projectSchema.virtual('id').get(function getProjectId() {
|
|
return this._id;
|
|
});
|
|
|
|
projectSchema.set('toJSON', {
|
|
virtuals: true
|
|
});
|
|
|
|
projectSchema.pre('save', function generateSlug(next) {
|
|
const project = this;
|
|
|
|
if (!project.slug) {
|
|
project.slug = slugify(project.name, '_');
|
|
}
|
|
|
|
return next();
|
|
});
|
|
|
|
/**
|
|
* Check if slug is unique for this user's projects
|
|
*/
|
|
projectSchema.methods.isSlugUnique = async function isSlugUnique(cb) {
|
|
const project = this;
|
|
const hasCallback = typeof cb === 'function';
|
|
|
|
try {
|
|
const docsWithSlug = await project.model('Project')
|
|
.find({ user: project.user, slug: project.slug }, '_id')
|
|
.exec();
|
|
|
|
const result = {
|
|
isUnique: docsWithSlug.length === 0,
|
|
conflictingIds: docsWithSlug.map(d => d._id) || []
|
|
};
|
|
|
|
if (hasCallback) {
|
|
cb(null, result);
|
|
}
|
|
|
|
return result;
|
|
} catch (err) {
|
|
if (hasCallback) {
|
|
cb(err, null);
|
|
}
|
|
|
|
throw err;
|
|
}
|
|
};
|
|
|
|
export default mongoose.model('Project', projectSchema);
|