Files
payload/src/collections/init.ts
2022-09-22 10:49:49 -04:00

124 lines
4.3 KiB
TypeScript

import mongoose, { UpdateAggregationStage, UpdateQuery } from 'mongoose';
import paginate from 'mongoose-paginate-v2';
import express from 'express';
import passport from 'passport';
import passportLocalMongoose from 'passport-local-mongoose';
import { buildVersionCollectionFields } from '../versions/buildCollectionFields';
import buildQueryPlugin from '../mongoose/buildQuery';
import apiKeyStrategy from '../auth/strategies/apiKey';
import buildCollectionSchema from './buildSchema';
import buildSchema from '../mongoose/buildSchema';
import bindCollectionMiddleware from './bindCollection';
import { CollectionModel, SanitizedCollectionConfig } from './config/types';
import { Payload } from '../index';
import { getVersionsModelName } from '../versions/getVersionsModelName';
import mountEndpoints from '../express/mountEndpoints';
import buildEndpoints from './buildEndpoints';
export default function registerCollections(ctx: Payload): void {
ctx.config.collections = ctx.config.collections.map((collection: SanitizedCollectionConfig) => {
const formattedCollection = collection;
const schema = buildCollectionSchema(formattedCollection, ctx.config);
if (collection.auth && !collection.auth.disableLocalStrategy) {
schema.plugin(passportLocalMongoose, {
usernameField: 'email',
});
const { maxLoginAttempts, lockTime } = collection.auth;
if (maxLoginAttempts > 0) {
type LoginSchema = {
loginAttempts: number
lockUntil: number
isLocked: boolean
};
// eslint-disable-next-line func-names
schema.methods.incLoginAttempts = function (this: mongoose.Document & LoginSchema, cb) {
// Expired lock, restart count at 1
if (this.lockUntil && this.lockUntil < Date.now()) {
return this.updateOne({
$set: { loginAttempts: 1 },
$unset: { lockUntil: 1 },
}, cb);
}
const updates: UpdateQuery<LoginSchema> = { $inc: { loginAttempts: 1 } };
// Lock the account if at max attempts and not already locked
if (this.loginAttempts + 1 >= maxLoginAttempts && !this.isLocked) {
updates.$set = { lockUntil: Date.now() + lockTime };
}
return this.updateOne(updates as UpdateAggregationStage, cb);
};
// eslint-disable-next-line func-names
schema.methods.resetLoginAttempts = function (cb) {
return this.updateOne({
$set: { loginAttempts: 0 },
$unset: { lockUntil: 1 },
}, cb);
};
}
}
if (collection.versions) {
const versionModelName = getVersionsModelName(collection);
const versionSchema = buildSchema(
ctx.config,
buildVersionCollectionFields(collection),
{
disableUnique: true,
options: {
timestamps: true,
},
},
);
versionSchema.plugin(paginate, { useEstimatedCount: true })
.plugin(buildQueryPlugin);
ctx.versions[collection.slug] = mongoose.model(versionModelName, versionSchema) as CollectionModel;
}
ctx.collections[formattedCollection.slug] = {
Model: mongoose.model(formattedCollection.slug, schema) as CollectionModel,
config: formattedCollection,
};
// If not local, open routes
if (!ctx.local) {
const router = express.Router();
const { slug } = collection;
router.all('*', bindCollectionMiddleware(ctx.collections[formattedCollection.slug]));
if (collection.auth) {
const AuthCollection = ctx.collections[formattedCollection.slug];
if (collection.auth.useAPIKey) {
passport.use(`${AuthCollection.config.slug}-api-key`, apiKeyStrategy(ctx, AuthCollection));
}
if (Array.isArray(collection.auth.strategies)) {
collection.auth.strategies.forEach(({ name, strategy }, index) => {
const passportStrategy = typeof strategy === 'object' ? strategy : strategy(ctx);
passport.use(`${AuthCollection.config.slug}-${name ?? index}`, passportStrategy);
});
}
}
const endpoints = buildEndpoints(collection);
mountEndpoints(ctx.express, router, endpoints);
ctx.router.use(`/${slug}`, router);
}
return formattedCollection;
});
}