225 lines
5.5 KiB
JavaScript
225 lines
5.5 KiB
JavaScript
const GenericDBApi = require('./base.api');
|
|
const db = require('../models');
|
|
const Utils = require('../utils');
|
|
const { getRuntimeProjectSlug } = require('./runtime-context');
|
|
|
|
const Sequelize = db.Sequelize;
|
|
const Op = Sequelize.Op;
|
|
|
|
class ProjectsDBApi extends GenericDBApi {
|
|
static get MODEL() {
|
|
return db.projects;
|
|
}
|
|
|
|
static get TABLE_NAME() {
|
|
return 'projects';
|
|
}
|
|
|
|
static get SEARCHABLE_FIELDS() {
|
|
return [
|
|
'name',
|
|
'slug',
|
|
'description',
|
|
'logo_url',
|
|
'favicon_url',
|
|
'og_image_url',
|
|
];
|
|
}
|
|
|
|
static get RANGE_FIELDS() {
|
|
return [];
|
|
}
|
|
|
|
static get ENUM_FIELDS() {
|
|
return [];
|
|
}
|
|
|
|
static get CSV_FIELDS() {
|
|
return [
|
|
'id',
|
|
'name',
|
|
'slug',
|
|
'description',
|
|
'logo_url',
|
|
'createdAt',
|
|
];
|
|
}
|
|
|
|
static get AUTOCOMPLETE_FIELD() {
|
|
return 'name';
|
|
}
|
|
|
|
static get ASSOCIATIONS() {
|
|
return [];
|
|
}
|
|
|
|
static getFieldMapping(data) {
|
|
return {
|
|
id: data.id || undefined,
|
|
name: data.name || null,
|
|
slug: data.slug || null,
|
|
description: data.description || null,
|
|
logo_url: data.logo_url || null,
|
|
favicon_url: data.favicon_url || null,
|
|
og_image_url: data.og_image_url || null,
|
|
};
|
|
}
|
|
|
|
static get DEFAULT_INCLUDES() {
|
|
return [];
|
|
}
|
|
|
|
static get ALL_INCLUDES() {
|
|
return [
|
|
{ association: 'project_memberships_project' },
|
|
{ association: 'assets_project' },
|
|
{ association: 'presigned_url_requests_project' },
|
|
{ association: 'tour_pages_project' },
|
|
{ association: 'project_audio_tracks_project' },
|
|
{ association: 'publish_events_project' },
|
|
{ association: 'pwa_caches_project' },
|
|
{ association: 'access_logs_project' },
|
|
];
|
|
}
|
|
|
|
static async findBy(where, options = {}) {
|
|
const transaction = options.transaction;
|
|
const runtimeProjectSlug = getRuntimeProjectSlug(options);
|
|
const queryWhere = { ...where };
|
|
|
|
// Runtime access: filter by project slug
|
|
// Skip if finding by ID (unambiguous lookup)
|
|
if (runtimeProjectSlug && !where.id) {
|
|
queryWhere.slug = runtimeProjectSlug;
|
|
}
|
|
|
|
const include =
|
|
options.include !== undefined ? options.include : this.DEFAULT_INCLUDES;
|
|
|
|
const record = await this.MODEL.findOne({
|
|
where: queryWhere,
|
|
transaction,
|
|
include,
|
|
});
|
|
|
|
if (!record) return null;
|
|
return record.get({ plain: true });
|
|
}
|
|
|
|
/**
|
|
* Create a new project and auto-snapshot global element defaults
|
|
*/
|
|
static async create(data, options = {}) {
|
|
const transaction = options.transaction;
|
|
|
|
// Create the project using parent's create
|
|
const project = await super.create(data, options);
|
|
|
|
// Auto-snapshot global element defaults to the new project
|
|
try {
|
|
const Project_element_defaultsDBApi = require('./project_element_defaults');
|
|
await Project_element_defaultsDBApi.snapshotGlobalDefaults(project.id, {
|
|
...options,
|
|
transaction,
|
|
});
|
|
} catch (error) {
|
|
// Log but don't fail project creation if snapshot fails
|
|
console.error(
|
|
'Failed to snapshot global element defaults to project:',
|
|
error,
|
|
);
|
|
}
|
|
|
|
return project;
|
|
}
|
|
|
|
static async findAll(filter = {}, options = {}) {
|
|
filter = filter || {};
|
|
const limit = filter.limit || 0;
|
|
const currentPage = +filter.page || 0;
|
|
const offset = currentPage * limit;
|
|
|
|
let where = {};
|
|
let include = [];
|
|
|
|
if (filter.id) {
|
|
where.id = Utils.uuid(filter.id);
|
|
}
|
|
|
|
for (const field of this.SEARCHABLE_FIELDS) {
|
|
if (filter[field]) {
|
|
where[Op.and] = Utils.ilike(this.TABLE_NAME, field, filter[field]);
|
|
}
|
|
}
|
|
|
|
for (const field of this.RANGE_FIELDS) {
|
|
const rangeKey = `${field}Range`;
|
|
if (filter[rangeKey]) {
|
|
const [start, end] = filter[rangeKey];
|
|
if (start !== undefined && start !== null && start !== '') {
|
|
where[field] = { ...where[field], [Op.gte]: start };
|
|
}
|
|
if (end !== undefined && end !== null && end !== '') {
|
|
where[field] = { ...where[field], [Op.lte]: end };
|
|
}
|
|
}
|
|
}
|
|
|
|
for (const field of this.ENUM_FIELDS) {
|
|
if (filter[field] !== undefined) {
|
|
where[field] = filter[field];
|
|
}
|
|
}
|
|
|
|
if (filter.active !== undefined) {
|
|
where.active = filter.active === true || filter.active === 'true';
|
|
}
|
|
|
|
if (filter.createdAtRange) {
|
|
const [start, end] = filter.createdAtRange;
|
|
if (start !== undefined && start !== null && start !== '') {
|
|
where.createdAt = { ...where.createdAt, [Op.gte]: start };
|
|
}
|
|
if (end !== undefined && end !== null && end !== '') {
|
|
where.createdAt = { ...where.createdAt, [Op.lte]: end };
|
|
}
|
|
}
|
|
|
|
// Runtime access: filter by project slug
|
|
const runtimeProjectSlug = getRuntimeProjectSlug(options);
|
|
|
|
if (runtimeProjectSlug) {
|
|
where.slug = runtimeProjectSlug;
|
|
}
|
|
|
|
const queryOptions = {
|
|
where,
|
|
include,
|
|
distinct: true,
|
|
order:
|
|
filter.field && filter.sort
|
|
? [[filter.field, filter.sort]]
|
|
: [['createdAt', 'desc']],
|
|
transaction: options.transaction,
|
|
};
|
|
|
|
if (!options.countOnly) {
|
|
queryOptions.limit = limit ? Number(limit) : undefined;
|
|
queryOptions.offset = offset ? Number(offset) : undefined;
|
|
}
|
|
|
|
try {
|
|
const { rows, count } = await this.MODEL.findAndCountAll(queryOptions);
|
|
return {
|
|
rows: options.countOnly ? [] : rows,
|
|
count,
|
|
};
|
|
} catch (error) {
|
|
console.error('Error executing query:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = ProjectsDBApi;
|