Compare commits

...

11 Commits

Author SHA1 Message Date
Dmitri
e890ccf2ed improved project structure (DB, BE, FE) 2026-03-19 07:12:29 +04:00
Dmitri
70e3c28f6a updated dependencies 2026-03-18 11:53:34 +04:00
Dmitri
5ec464e6ce gitignore updated 2026-03-18 11:00:22 +04:00
Flatlogic Bot
1b5c13c8ae constructor (UI elements basic) 2026-03-18 06:43:39 +00:00
Flatlogic Bot
b4fe0dde81 Autosave: 20260318-063526 2026-03-18 06:35:27 +00:00
Flatlogic Bot
06dd524cd0 Revert to version 4268405 2026-03-17 15:35:44 +00:00
Flatlogic Bot
2680417aae Autosave: 20260317-153203 2026-03-17 15:32:03 +00:00
Flatlogic Bot
42684051c3 Basic constructor 2026-03-17 15:26:24 +00:00
Flatlogic Bot
8a20fdbd9e Autosave: 20260317-145604 2026-03-17 14:56:05 +00:00
Flatlogic Bot
a8942e7c5d Autosave: 20260317-124943 2026-03-17 12:49:43 +00:00
Flatlogic Bot
d3b659f3bc Autosave: 20260317-121506 2026-03-17 12:15:06 +00:00
400 changed files with 39849 additions and 103062 deletions

3
.gitignore vendored
View File

@ -4,3 +4,6 @@ node_modules/
*/node_modules/
**/node_modules/
*/build/
package-lock.json
CLAUDE.md
.claude/

18071
backend/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -11,47 +11,52 @@
"watch": "node watcher.js"
},
"dependencies": {
"@aws-sdk/client-s3": "^3.1010.0",
"@google-cloud/storage": "^5.18.2",
"axios": "^1.6.7",
"bcrypt": "5.1.1",
"@aws-sdk/client-s3": "^3.1011.0",
"@google-cloud/storage": "^7.0.0",
"axios": "^1.13.0",
"bcrypt": "^6.0.0",
"chokidar": "^4.0.3",
"cors": "2.8.5",
"csv-parser": "^3.0.0",
"cors": "^2.8.6",
"csv-parser": "^3.2.0",
"dotenv": "^16.4.0",
"express": "4.18.2",
"express-validator": "^7.0.0",
"formidable": "1.2.2",
"helmet": "4.1.1",
"helmet": "^8.0.0",
"joi": "^17.13.0",
"json2csv": "^5.0.7",
"jsonwebtoken": "8.5.1",
"lodash": "4.17.21",
"jsonwebtoken": "^9.0.0",
"lodash": "^4.17.23",
"moment": "2.30.1",
"multer": "^1.4.4",
"multer": "^2.0.0",
"mysql2": "2.2.5",
"nodemailer": "6.9.9",
"passport": "^0.7.0",
"passport-google-oauth2": "^0.2.0",
"passport-jwt": "^4.0.1",
"passport-microsoft": "^0.1.0",
"pg": "8.4.1",
"passport-microsoft": "^2.0.0",
"pg": "^8.20.0",
"pino": "^9.0.0",
"pino-pretty": "^11.0.0",
"pg-hstore": "2.3.4",
"sequelize": "6.35.2",
"sequelize": "^6.37.0",
"sequelize-json-schema": "^2.1.1",
"sqlite": "4.0.15",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.0",
"tedious": "^18.2.4"
"tedious": "^18.6.0"
},
"engines": {
"node": ">=18"
},
"private": true,
"devDependencies": {
"cross-env": "7.0.3",
"eslint": "^8.23.1",
"cross-env": "^7.0.3",
"eslint": "^8.57.0",
"eslint-plugin-import": "^2.29.1",
"mocha": "8.1.3",
"node-mocks-http": "1.9.0",
"nodemon": "2.0.5",
"sequelize-cli": "6.6.2"
"mocha": "^10.0.0",
"node-mocks-http": "^1.17.0",
"nodemon": "^3.0.0",
"sequelize-cli": "^6.6.5"
}
}

View File

@ -1,37 +1,10 @@
const os = require('os');
const fs = require('fs');
const path = require('path');
const envFilePath = path.resolve(__dirname, '../.env');
require('dotenv').config({ path: path.resolve(__dirname, '../.env') });
if (fs.existsSync(envFilePath)) {
const envContent = fs.readFileSync(envFilePath, 'utf8');
envContent.split('\n').forEach((line) => {
const trimmedLine = line.trim();
if (!trimmedLine || trimmedLine.startsWith('#')) {
return;
}
const delimiterIndex = trimmedLine.indexOf('=');
if (delimiterIndex === -1) {
return;
}
const key = trimmedLine.slice(0, delimiterIndex).trim();
const rawValue = trimmedLine.slice(delimiterIndex + 1).trim();
if (!key || Object.prototype.hasOwnProperty.call(process.env, key)) {
return;
}
const unquotedValue = rawValue.replace(/^['"]|['"]$/g, '');
process.env[key] = unquotedValue;
});
}
const { validateEnv } = require('./utils/env-validation');
validateEnv();
const config = {
gcloud: {
@ -48,9 +21,9 @@ const config = {
bcrypt: {
saltRounds: 12
},
admin_pass: "88dbeaf8",
user_pass: "c3baadeda5c6",
admin_email: "admin@flatlogic.com",
admin_pass: process.env.ADMIN_PASS || "88dbeaf8",
user_pass: process.env.USER_PASS || "c3baadeda5c6",
admin_email: process.env.ADMIN_EMAIL || "admin@flatlogic.com",
providers: {
LOCAL: 'local',
GOOGLE: 'google',

View File

@ -1,297 +1,76 @@
const GenericDBApi = require('./base.api');
const db = require('../models');
const Utils = require('../utils');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class Access_logsDBApi {
class Access_logsDBApi extends GenericDBApi {
static get MODEL() {
return db.access_logs;
}
static get TABLE_NAME() {
return 'access_logs';
}
static get SEARCHABLE_FIELDS() {
return ['path', 'ip_address', 'user_agent'];
}
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
static get RANGE_FIELDS() {
return ['accessed_at'];
}
const access_logs = await db.access_logs.create(
{
static get ENUM_FIELDS() {
return ['environment'];
}
static get CSV_FIELDS() {
return ['id', 'environment', 'path', 'ip_address', 'user_agent', 'accessed_at', 'createdAt'];
}
static get AUTOCOMPLETE_FIELD() {
return 'path';
}
static get ASSOCIATIONS() {
return [
{ field: 'project', setter: 'setProject', isArray: false },
{ field: 'user', setter: 'setUser', isArray: false },
];
}
static get FIND_BY_INCLUDES() {
return [
{ association: 'project' },
{ association: 'user' },
];
}
static getFieldMapping(data) {
return {
id: data.id || undefined,
environment: data.environment
||
null
,
path: data.path
||
null
,
ip_address: data.ip_address
||
null
,
user_agent: data.user_agent
||
null
,
accessed_at: data.accessed_at
||
null
,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
await access_logs.setProject( data.project || null, {
transaction,
});
await access_logs.setUser( data.user || null, {
transaction,
});
return access_logs;
environment: data.environment || null,
path: data.path || null,
ip_address: data.ip_address || null,
user_agent: data.user_agent || null,
accessed_at: data.accessed_at || null,
};
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
// Prepare data - wrapping individual data transformations in a map() method
const access_logsData = data.map((item, index) => ({
id: item.id || undefined,
environment: item.environment
||
null
,
path: item.path
||
null
,
ip_address: item.ip_address
||
null
,
user_agent: item.user_agent
||
null
,
accessed_at: item.accessed_at
||
null
,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const access_logs = await db.access_logs.bulkCreate(access_logsData, { transaction });
// For each item created, replace relation files
return access_logs;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const access_logs = await db.access_logs.findByPk(id, {transaction});
const updatePayload = {};
if (data.environment !== undefined) updatePayload.environment = data.environment;
if (data.path !== undefined) updatePayload.path = data.path;
if (data.ip_address !== undefined) updatePayload.ip_address = data.ip_address;
if (data.user_agent !== undefined) updatePayload.user_agent = data.user_agent;
if (data.accessed_at !== undefined) updatePayload.accessed_at = data.accessed_at;
updatePayload.updatedById = currentUser.id;
await access_logs.update(updatePayload, {transaction});
if (data.project !== undefined) {
await access_logs.setProject(
data.project,
{ transaction }
);
}
if (data.user !== undefined) {
await access_logs.setUser(
data.user,
{ transaction }
);
}
return access_logs;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const access_logs = await db.access_logs.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (transaction) => {
for (const record of access_logs) {
await record.update(
{deletedBy: currentUser.id},
{transaction}
);
}
for (const record of access_logs) {
await record.destroy({transaction});
}
});
return access_logs;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const access_logs = await db.access_logs.findByPk(id, options);
await access_logs.update({
deletedBy: currentUser.id
}, {
transaction,
});
await access_logs.destroy({
transaction
});
return access_logs;
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
const access_logs = await db.access_logs.findOne({
where,
transaction,
});
if (!access_logs) {
return access_logs;
}
const output = access_logs.get({plain: true});
output.project = await access_logs.getProject({
transaction
});
output.user = await access_logs.getUser({
transaction
});
return output;
}
static async findAll(
filter,
options
) {
static async findAll(filter = {}, options = {}) {
filter = filter || {};
const limit = filter.limit || 0;
let offset = 0;
const currentPage = +filter.page || 0;
const offset = currentPage * limit;
let where = {};
const currentPage = +filter.page;
offset = currentPage * limit;
let include = [
{
model: db.projects,
as: 'project',
where: filter.project ? {
[Op.or]: [
{ id: { [Op.in]: filter.project.split('|').map(term => Utils.uuid(term)) } },
@ -302,13 +81,10 @@ module.exports = class Access_logsDBApi {
},
]
} : {},
},
{
model: db.users,
as: 'user',
where: filter.user ? {
[Op.or]: [
{ id: { [Op.in]: filter.user.split('|').map(term => Utils.uuid(term)) } },
@ -319,135 +95,51 @@ module.exports = class Access_logsDBApi {
},
]
} : {},
},
];
if (filter) {
if (filter.id) {
where = {
...where,
['id']: Utils.uuid(filter.id),
};
where.id = Utils.uuid(filter.id);
}
if (filter.path) {
where = {
...where,
[Op.and]: Utils.ilike(
'access_logs',
'path',
filter.path,
),
};
for (const field of this.SEARCHABLE_FIELDS) {
if (filter[field]) {
where[Op.and] = Utils.ilike(this.TABLE_NAME, field, filter[field]);
}
}
if (filter.ip_address) {
where = {
...where,
[Op.and]: Utils.ilike(
'access_logs',
'ip_address',
filter.ip_address,
),
};
}
if (filter.user_agent) {
where = {
...where,
[Op.and]: Utils.ilike(
'access_logs',
'user_agent',
filter.user_agent,
),
};
}
if (filter.accessed_atRange) {
const [start, end] = filter.accessed_atRange;
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 = {
...where,
accessed_at: {
...where.accessed_at,
[Op.gte]: start,
},
};
where[field] = { ...where[field], [Op.gte]: start };
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
accessed_at: {
...where.accessed_at,
[Op.lte]: 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 = {
...where,
active: filter.active === true || filter.active === 'true'
};
where.active = filter.active === true || filter.active === 'true';
}
if (filter.environment) {
where = {
...where,
environment: filter.environment,
};
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.gte]: start,
},
};
where.createdAt = { ...where.createdAt, [Op.gte]: start };
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.lte]: end,
},
};
where.createdAt = { ...where.createdAt, [Op.lte]: end };
}
}
}
const queryOptions = {
where,
@ -456,59 +148,25 @@ module.exports = class Access_logsDBApi {
order: filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log
transaction: options.transaction,
};
if (!options?.countOnly) {
if (!options.countOnly) {
queryOptions.limit = limit ? Number(limit) : undefined;
queryOptions.offset = offset ? Number(offset) : undefined;
}
try {
const { rows, count } = await db.access_logs.findAndCountAll(queryOptions);
const { rows, count } = await this.MODEL.findAndCountAll(queryOptions);
return {
rows: options?.countOnly ? [] : rows,
count: count
rows: options.countOnly ? [] : rows,
count,
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
static async findAllAutocomplete(query, limit, offset, ) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
Utils.ilike(
'access_logs',
'path',
query,
),
],
};
}
const records = await db.access_logs.findAll({
attributes: [ 'id', 'path' ],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
orderBy: [['path', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.path,
}));
}
};
module.exports = Access_logsDBApi;

View File

@ -1,279 +1,72 @@
const GenericDBApi = require('./base.api');
const db = require('../models');
const Utils = require('../utils');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class Asset_variantsDBApi {
class Asset_variantsDBApi extends GenericDBApi {
static get MODEL() {
return db.asset_variants;
}
static get TABLE_NAME() {
return 'asset_variants';
}
static get SEARCHABLE_FIELDS() {
return ['cdn_url'];
}
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
static get RANGE_FIELDS() {
return ['width_px', 'height_px', 'size_mb'];
}
const asset_variants = await db.asset_variants.create(
{
static get ENUM_FIELDS() {
return ['variant_type'];
}
static get CSV_FIELDS() {
return ['id', 'variant_type', 'cdn_url', 'width_px', 'height_px', 'size_mb', 'createdAt'];
}
static get AUTOCOMPLETE_FIELD() {
return 'variant_type';
}
static get ASSOCIATIONS() {
return [
{ field: 'asset', setter: 'setAsset', isArray: false },
];
}
static get FIND_BY_INCLUDES() {
return [{ association: 'asset' }];
}
static getFieldMapping(data) {
return {
id: data.id || undefined,
variant_type: data.variant_type
||
null
,
cdn_url: data.cdn_url
||
null
,
width_px: data.width_px
||
null
,
height_px: data.height_px
||
null
,
size_mb: data.size_mb
||
null
,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
await asset_variants.setAsset( data.asset || null, {
transaction,
});
return asset_variants;
variant_type: data.variant_type || null,
cdn_url: data.cdn_url || null,
width_px: data.width_px || null,
height_px: data.height_px || null,
size_mb: data.size_mb || null,
};
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
// Prepare data - wrapping individual data transformations in a map() method
const asset_variantsData = data.map((item, index) => ({
id: item.id || undefined,
variant_type: item.variant_type
||
null
,
cdn_url: item.cdn_url
||
null
,
width_px: item.width_px
||
null
,
height_px: item.height_px
||
null
,
size_mb: item.size_mb
||
null
,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const asset_variants = await db.asset_variants.bulkCreate(asset_variantsData, { transaction });
// For each item created, replace relation files
return asset_variants;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const asset_variants = await db.asset_variants.findByPk(id, {transaction});
const updatePayload = {};
if (data.variant_type !== undefined) updatePayload.variant_type = data.variant_type;
if (data.cdn_url !== undefined) updatePayload.cdn_url = data.cdn_url;
if (data.width_px !== undefined) updatePayload.width_px = data.width_px;
if (data.height_px !== undefined) updatePayload.height_px = data.height_px;
if (data.size_mb !== undefined) updatePayload.size_mb = data.size_mb;
updatePayload.updatedById = currentUser.id;
await asset_variants.update(updatePayload, {transaction});
if (data.asset !== undefined) {
await asset_variants.setAsset(
data.asset,
{ transaction }
);
}
return asset_variants;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const asset_variants = await db.asset_variants.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (transaction) => {
for (const record of asset_variants) {
await record.update(
{deletedBy: currentUser.id},
{transaction}
);
}
for (const record of asset_variants) {
await record.destroy({transaction});
}
});
return asset_variants;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const asset_variants = await db.asset_variants.findByPk(id, options);
await asset_variants.update({
deletedBy: currentUser.id
}, {
transaction,
});
await asset_variants.destroy({
transaction
});
return asset_variants;
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
const asset_variants = await db.asset_variants.findOne({
where,
transaction,
});
if (!asset_variants) {
return asset_variants;
}
const output = asset_variants.get({plain: true});
output.asset = await asset_variants.getAsset({
transaction
});
return output;
}
static async findAll(
filter,
options
) {
static async findAll(filter = {}, options = {}) {
filter = filter || {};
const limit = filter.limit || 0;
let offset = 0;
const currentPage = +filter.page || 0;
const offset = currentPage * limit;
let where = {};
const currentPage = +filter.page;
offset = currentPage * limit;
let include = [
{
model: db.assets,
as: 'asset',
where: filter.asset ? {
[Op.or]: [
{ id: { [Op.in]: filter.asset.split('|').map(term => Utils.uuid(term)) } },
@ -284,159 +77,51 @@ module.exports = class Asset_variantsDBApi {
},
]
} : {},
},
];
if (filter) {
if (filter.id) {
where = {
...where,
['id']: Utils.uuid(filter.id),
};
where.id = Utils.uuid(filter.id);
}
if (filter.cdn_url) {
where = {
...where,
[Op.and]: Utils.ilike(
'asset_variants',
'cdn_url',
filter.cdn_url,
),
};
for (const field of this.SEARCHABLE_FIELDS) {
if (filter[field]) {
where[Op.and] = Utils.ilike(this.TABLE_NAME, field, filter[field]);
}
}
if (filter.width_pxRange) {
const [start, end] = filter.width_pxRange;
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 = {
...where,
width_px: {
...where.width_px,
[Op.gte]: start,
},
};
where[field] = { ...where[field], [Op.gte]: start };
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
width_px: {
...where.width_px,
[Op.lte]: end,
},
};
where[field] = { ...where[field], [Op.lte]: end };
}
}
}
if (filter.height_pxRange) {
const [start, end] = filter.height_pxRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
height_px: {
...where.height_px,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
height_px: {
...where.height_px,
[Op.lte]: end,
},
};
for (const field of this.ENUM_FIELDS) {
if (filter[field] !== undefined) {
where[field] = filter[field];
}
}
if (filter.size_mbRange) {
const [start, end] = filter.size_mbRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
size_mb: {
...where.size_mb,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
size_mb: {
...where.size_mb,
[Op.lte]: end,
},
};
}
}
if (filter.active !== undefined) {
where = {
...where,
active: filter.active === true || filter.active === 'true'
};
where.active = filter.active === true || filter.active === 'true';
}
if (filter.variant_type) {
where = {
...where,
variant_type: filter.variant_type,
};
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.gte]: start,
},
};
where.createdAt = { ...where.createdAt, [Op.gte]: start };
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.lte]: end,
},
};
where.createdAt = { ...where.createdAt, [Op.lte]: end };
}
}
}
const queryOptions = {
where,
@ -445,59 +130,25 @@ module.exports = class Asset_variantsDBApi {
order: filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log
transaction: options.transaction,
};
if (!options?.countOnly) {
if (!options.countOnly) {
queryOptions.limit = limit ? Number(limit) : undefined;
queryOptions.offset = offset ? Number(offset) : undefined;
}
try {
const { rows, count } = await db.asset_variants.findAndCountAll(queryOptions);
const { rows, count } = await this.MODEL.findAndCountAll(queryOptions);
return {
rows: options?.countOnly ? [] : rows,
count: count
rows: options.countOnly ? [] : rows,
count,
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
static async findAllAutocomplete(query, limit, offset, ) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
Utils.ilike(
'asset_variants',
'variant_type',
query,
),
],
};
}
const records = await db.asset_variants.findAll({
attributes: [ 'id', 'variant_type' ],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
orderBy: [['variant_type', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.variant_type,
}));
}
};
module.exports = Asset_variantsDBApi;

View File

@ -1,391 +1,90 @@
const GenericDBApi = require('./base.api');
const db = require('../models');
const Utils = require('../utils');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class AssetsDBApi {
class AssetsDBApi extends GenericDBApi {
static get MODEL() {
return db.assets;
}
static get TABLE_NAME() {
return 'assets';
}
static get SEARCHABLE_FIELDS() {
return ['name', 'cdn_url', 'storage_key', 'mime_type', 'checksum'];
}
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
static get RANGE_FIELDS() {
return ['size_mb', 'width_px', 'height_px', 'duration_sec', 'deleted_at_time'];
}
const assets = await db.assets.create(
{
static get ENUM_FIELDS() {
return ['asset_type', 'type', 'is_public', 'is_deleted'];
}
static get CSV_FIELDS() {
return ['id', 'name', 'asset_type', 'type', 'cdn_url', 'storage_key', 'mime_type', 'size_mb', 'createdAt'];
}
static get AUTOCOMPLETE_FIELD() {
return 'name';
}
static get ASSOCIATIONS() {
return [
{ field: 'project', setter: 'setProject', isArray: false },
];
}
static get FIND_BY_INCLUDES() {
return [
{ association: 'asset_variants_asset' },
{ association: 'project' },
];
}
static get RELATION_FILTERS() {
return [
{ filterKey: 'project', model: db.projects, as: 'project', searchField: 'name' },
];
}
static getFieldMapping(data) {
return {
id: data.id || undefined,
name: data.name
||
null
,
asset_type: data.asset_type
||
null
,
cdn_url: data.cdn_url
||
null
,
storage_key: data.storage_key
||
null
,
mime_type: data.mime_type
||
null
,
size_mb: data.size_mb
||
null
,
width_px: data.width_px
||
null
,
height_px: data.height_px
||
null
,
duration_sec: data.duration_sec
||
null
,
checksum: data.checksum
||
null
,
is_public: data.is_public
||
false
,
is_deleted: data.is_deleted
||
false
,
deleted_at_time: data.deleted_at_time
||
null
,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
await assets.setProject( data.project || null, {
transaction,
});
return assets;
name: data.name || null,
asset_type: data.asset_type || null,
type: data.type || 'general',
cdn_url: data.cdn_url || null,
storage_key: data.storage_key || null,
mime_type: data.mime_type || null,
size_mb: data.size_mb || null,
width_px: data.width_px || null,
height_px: data.height_px || null,
duration_sec: data.duration_sec || null,
checksum: data.checksum || null,
is_public: data.is_public || false,
is_deleted: data.is_deleted || false,
deleted_at_time: data.deleted_at_time || null,
};
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
// Prepare data - wrapping individual data transformations in a map() method
const assetsData = data.map((item, index) => ({
id: item.id || undefined,
name: item.name
||
null
,
asset_type: item.asset_type
||
null
,
cdn_url: item.cdn_url
||
null
,
storage_key: item.storage_key
||
null
,
mime_type: item.mime_type
||
null
,
size_mb: item.size_mb
||
null
,
width_px: item.width_px
||
null
,
height_px: item.height_px
||
null
,
duration_sec: item.duration_sec
||
null
,
checksum: item.checksum
||
null
,
is_public: item.is_public
||
false
,
is_deleted: item.is_deleted
||
false
,
deleted_at_time: item.deleted_at_time
||
null
,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const assets = await db.assets.bulkCreate(assetsData, { transaction });
// For each item created, replace relation files
return assets;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const assets = await db.assets.findByPk(id, {transaction});
const updatePayload = {};
if (data.name !== undefined) updatePayload.name = data.name;
if (data.asset_type !== undefined) updatePayload.asset_type = data.asset_type;
if (data.cdn_url !== undefined) updatePayload.cdn_url = data.cdn_url;
if (data.storage_key !== undefined) updatePayload.storage_key = data.storage_key;
if (data.mime_type !== undefined) updatePayload.mime_type = data.mime_type;
if (data.size_mb !== undefined) updatePayload.size_mb = data.size_mb;
if (data.width_px !== undefined) updatePayload.width_px = data.width_px;
if (data.height_px !== undefined) updatePayload.height_px = data.height_px;
if (data.duration_sec !== undefined) updatePayload.duration_sec = data.duration_sec;
if (data.checksum !== undefined) updatePayload.checksum = data.checksum;
if (data.is_public !== undefined) updatePayload.is_public = data.is_public;
if (data.is_deleted !== undefined) updatePayload.is_deleted = data.is_deleted;
if (data.deleted_at_time !== undefined) updatePayload.deleted_at_time = data.deleted_at_time;
updatePayload.updatedById = currentUser.id;
await assets.update(updatePayload, {transaction});
if (data.project !== undefined) {
await assets.setProject(
data.project,
{ transaction }
);
}
return assets;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const assets = await db.assets.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (transaction) => {
for (const record of assets) {
await record.update(
{deletedBy: currentUser.id},
{transaction}
);
}
for (const record of assets) {
await record.destroy({transaction});
}
});
return assets;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const assets = await db.assets.findByPk(id, options);
await assets.update({
deletedBy: currentUser.id
}, {
transaction,
});
await assets.destroy({
transaction
});
return assets;
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
const assets = await db.assets.findOne({
where,
transaction,
});
if (!assets) {
return assets;
}
const output = assets.get({plain: true});
output.asset_variants_asset = await assets.getAsset_variants_asset({
transaction
});
output.project = await assets.getProject({
transaction
});
return output;
}
static async findAll(
filter,
options
) {
static async findAll(filter = {}, options = {}) {
filter = filter || {};
const limit = filter.limit || 0;
let offset = 0;
const currentPage = +filter.page || 0;
const offset = currentPage * limit;
let where = {};
const currentPage = +filter.page;
offset = currentPage * limit;
let include = [
{
model: db.projects,
as: 'project',
where: filter.project ? {
[Op.or]: [
{ id: { [Op.in]: filter.project.split('|').map(term => Utils.uuid(term)) } },
@ -396,265 +95,51 @@ module.exports = class AssetsDBApi {
},
]
} : {},
},
];
if (filter) {
if (filter.id) {
where = {
...where,
['id']: Utils.uuid(filter.id),
};
where.id = Utils.uuid(filter.id);
}
if (filter.name) {
where = {
...where,
[Op.and]: Utils.ilike(
'assets',
'name',
filter.name,
),
};
for (const field of this.SEARCHABLE_FIELDS) {
if (filter[field]) {
where[Op.and] = Utils.ilike(this.TABLE_NAME, field, filter[field]);
}
}
if (filter.cdn_url) {
where = {
...where,
[Op.and]: Utils.ilike(
'assets',
'cdn_url',
filter.cdn_url,
),
};
}
if (filter.storage_key) {
where = {
...where,
[Op.and]: Utils.ilike(
'assets',
'storage_key',
filter.storage_key,
),
};
}
if (filter.mime_type) {
where = {
...where,
[Op.and]: Utils.ilike(
'assets',
'mime_type',
filter.mime_type,
),
};
}
if (filter.checksum) {
where = {
...where,
[Op.and]: Utils.ilike(
'assets',
'checksum',
filter.checksum,
),
};
}
if (filter.size_mbRange) {
const [start, end] = filter.size_mbRange;
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 = {
...where,
size_mb: {
...where.size_mb,
[Op.gte]: start,
},
};
where[field] = { ...where[field], [Op.gte]: start };
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
size_mb: {
...where.size_mb,
[Op.lte]: end,
},
};
where[field] = { ...where[field], [Op.lte]: end };
}
}
}
if (filter.width_pxRange) {
const [start, end] = filter.width_pxRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
width_px: {
...where.width_px,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
width_px: {
...where.width_px,
[Op.lte]: end,
},
};
for (const field of this.ENUM_FIELDS) {
if (filter[field] !== undefined) {
where[field] = filter[field];
}
}
if (filter.height_pxRange) {
const [start, end] = filter.height_pxRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
height_px: {
...where.height_px,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
height_px: {
...where.height_px,
[Op.lte]: end,
},
};
}
}
if (filter.duration_secRange) {
const [start, end] = filter.duration_secRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
duration_sec: {
...where.duration_sec,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
duration_sec: {
...where.duration_sec,
[Op.lte]: end,
},
};
}
}
if (filter.deleted_at_timeRange) {
const [start, end] = filter.deleted_at_timeRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
deleted_at_time: {
...where.deleted_at_time,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
deleted_at_time: {
...where.deleted_at_time,
[Op.lte]: end,
},
};
}
}
if (filter.active !== undefined) {
where = {
...where,
active: filter.active === true || filter.active === 'true'
};
where.active = filter.active === true || filter.active === 'true';
}
if (filter.asset_type) {
where = {
...where,
asset_type: filter.asset_type,
};
}
if (filter.is_public) {
where = {
...where,
is_public: filter.is_public,
};
}
if (filter.is_deleted) {
where = {
...where,
is_deleted: filter.is_deleted,
};
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.gte]: start,
},
};
where.createdAt = { ...where.createdAt, [Op.gte]: start };
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.lte]: end,
},
};
where.createdAt = { ...where.createdAt, [Op.lte]: end };
}
}
}
const queryOptions = {
where,
@ -663,59 +148,25 @@ module.exports = class AssetsDBApi {
order: filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log
transaction: options.transaction,
};
if (!options?.countOnly) {
if (!options.countOnly) {
queryOptions.limit = limit ? Number(limit) : undefined;
queryOptions.offset = offset ? Number(offset) : undefined;
}
try {
const { rows, count } = await db.assets.findAndCountAll(queryOptions);
const { rows, count } = await this.MODEL.findAndCountAll(queryOptions);
return {
rows: options?.countOnly ? [] : rows,
count: count
rows: options.countOnly ? [] : rows,
count,
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
static async findAllAutocomplete(query, limit, offset, ) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
Utils.ilike(
'assets',
'name',
query,
),
],
};
}
const records = await db.assets.findAll({
attributes: [ 'id', 'name' ],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
orderBy: [['name', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.name,
}));
}
};
module.exports = AssetsDBApi;

View File

@ -0,0 +1,313 @@
const db = require('../models');
const Utils = require('../utils');
const { parse } = require('json2csv');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
class GenericDBApi {
static get MODEL() {
throw new Error('MODEL must be defined in subclass');
}
static get TABLE_NAME() {
return this.MODEL.getTableName();
}
static get SEARCHABLE_FIELDS() {
return [];
}
static get RANGE_FIELDS() {
return [];
}
static get ENUM_FIELDS() {
return [];
}
static get RELATION_FILTERS() {
return [];
}
static get CSV_FIELDS() {
return ['id', 'createdAt'];
}
static get AUTOCOMPLETE_FIELD() {
return 'name';
}
static get ASSOCIATIONS() {
return [];
}
static get FIND_BY_INCLUDES() {
return [];
}
static get FIND_ALL_INCLUDES() {
return [];
}
static getFieldMapping(data) {
return data;
}
static async create(data, options = {}) {
const currentUser = options.currentUser || { id: null };
const transaction = options.transaction;
const mappedData = this.getFieldMapping(data);
const record = await this.MODEL.create(
{
...mappedData,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction }
);
for (const assoc of this.ASSOCIATIONS) {
if (data[assoc.field] !== undefined) {
await record[assoc.setter](data[assoc.field] || (assoc.isArray ? [] : null), { transaction });
}
}
return record;
}
static async bulkImport(data, options = {}) {
const currentUser = options.currentUser || { id: null };
const transaction = options.transaction;
const recordsData = data.map((item, index) => ({
...this.getFieldMapping(item),
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
return this.MODEL.bulkCreate(recordsData, { transaction });
}
static async update(id, data, options = {}) {
const currentUser = options.currentUser || { id: null };
const transaction = options.transaction;
const record = await this.MODEL.findByPk(id, { transaction });
if (!record) {
throw { status: 404, message: `${this.TABLE_NAME} not found` };
}
const updatePayload = { updatedById: currentUser.id };
const mappedData = this.getFieldMapping(data);
for (const [key, value] of Object.entries(mappedData)) {
if (value !== undefined) {
updatePayload[key] = value;
}
}
await record.update(updatePayload, { transaction });
for (const assoc of this.ASSOCIATIONS) {
if (data[assoc.field] !== undefined) {
await record[assoc.setter](data[assoc.field], { transaction });
}
}
return record;
}
static async deleteByIds(ids, options = {}) {
const currentUser = options.currentUser || { id: null };
const transaction = options.transaction;
const records = await this.MODEL.findAll({
where: { id: { [Op.in]: ids } },
transaction,
});
await db.sequelize.transaction(async (tx) => {
for (const record of records) {
await record.update({ deletedBy: currentUser.id }, { transaction: tx });
}
for (const record of records) {
await record.destroy({ transaction: tx });
}
});
return records;
}
static async remove(id, options = {}) {
const currentUser = options.currentUser || { id: null };
const transaction = options.transaction;
const record = await this.MODEL.findByPk(id, { transaction });
if (!record) {
throw { status: 404, message: `${this.TABLE_NAME} not found` };
}
await record.update({ deletedBy: currentUser.id }, { transaction });
await record.destroy({ transaction });
return record;
}
static async findBy(where, options = {}) {
const transaction = options.transaction;
const record = await this.MODEL.findOne({
where,
transaction,
include: this.FIND_BY_INCLUDES,
});
if (!record) {
return null;
}
return record.get({ plain: true });
}
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 = [...this.FIND_ALL_INCLUDES];
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 };
}
}
for (const rel of this.RELATION_FILTERS) {
if (filter[rel.filterKey]) {
const searchTerms = filter[rel.filterKey].split('|');
const relInclude = {
model: rel.model,
as: rel.as,
required: searchTerms.length > 0,
where: searchTerms.length > 0 ? {
[Op.or]: [
{ id: { [Op.in]: searchTerms.map(term => Utils.uuid(term)) } },
rel.searchField ? {
[rel.searchField]: {
[Op.or]: searchTerms.map(term => ({ [Op.iLike]: `%${term}%` }))
}
} : {}
]
} : undefined
};
include = [relInclude, ...include];
}
}
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;
}
}
static async findAllAutocomplete(query, limit, offset) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ id: Utils.uuid(query) },
Utils.ilike(this.TABLE_NAME, this.AUTOCOMPLETE_FIELD, query),
],
};
}
const records = await this.MODEL.findAll({
attributes: ['id', this.AUTOCOMPLETE_FIELD],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
order: [[this.AUTOCOMPLETE_FIELD, 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record[this.AUTOCOMPLETE_FIELD],
}));
}
static toCSV(rows) {
const opts = { fields: this.CSV_FIELDS };
return parse(rows, opts);
}
}
module.exports = GenericDBApi;

View File

@ -1,4 +1,4 @@
const GenericDBApi = require('./base.api');
const db = require('../models');
const Utils = require('../utils');
const {
@ -6,230 +6,63 @@ const {
getRuntimeProjectSlug,
} = require('./runtime-context');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class Page_elementsDBApi {
class Page_elementsDBApi extends GenericDBApi {
static get MODEL() {
return db.page_elements;
}
static get TABLE_NAME() {
return 'page_elements';
}
static get SEARCHABLE_FIELDS() {
return ['name', 'style_json', 'content_json'];
}
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
static get RANGE_FIELDS() {
return ['sort_order', 'x_percent', 'y_percent', 'width_percent', 'height_percent', 'rotation_deg'];
}
const page_elements = await db.page_elements.create(
{
static get ENUM_FIELDS() {
return ['element_type', 'is_visible'];
}
static get CSV_FIELDS() {
return ['id', 'element_type', 'name', 'sort_order', 'is_visible', 'x_percent', 'y_percent', 'createdAt'];
}
static get AUTOCOMPLETE_FIELD() {
return 'name';
}
static get ASSOCIATIONS() {
return [
{ field: 'page', setter: 'setPage', isArray: false },
];
}
static getFieldMapping(data) {
return {
id: data.id || undefined,
element_type: data.element_type ?? null,
name: data.name ?? null,
sort_order: data.sort_order ?? 0,
is_visible: data.is_visible ?? false,
x_percent: data.x_percent ?? null,
y_percent: data.y_percent ?? null,
width_percent: data.width_percent ?? null,
height_percent: data.height_percent ?? null,
rotation_deg: data.rotation_deg ?? null,
style_json: data.style_json ?? null,
content_json: data.content_json ?? null,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
await page_elements.setPage( data.page || null, {
transaction,
});
return page_elements;
};
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
// Prepare data - wrapping individual data transformations in a map() method
const page_elementsData = data.map((item, index) => ({
id: item.id || undefined,
element_type: item.element_type ?? null,
name: item.name ?? null,
sort_order: item.sort_order ?? 0,
is_visible: item.is_visible ?? false,
x_percent: item.x_percent ?? null,
y_percent: item.y_percent ?? null,
width_percent: item.width_percent ?? null,
height_percent: item.height_percent ?? null,
rotation_deg: item.rotation_deg ?? null,
style_json: item.style_json ?? null,
content_json: item.content_json ?? null,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const page_elements = await db.page_elements.bulkCreate(page_elementsData, { transaction });
// For each item created, replace relation files
return page_elements;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const page_elements = await db.page_elements.findByPk(id, {transaction});
const updatePayload = {};
if (data.element_type !== undefined) updatePayload.element_type = data.element_type;
if (data.name !== undefined) updatePayload.name = data.name;
if (data.sort_order !== undefined) updatePayload.sort_order = data.sort_order;
if (data.is_visible !== undefined) updatePayload.is_visible = data.is_visible;
if (data.x_percent !== undefined) updatePayload.x_percent = data.x_percent;
if (data.y_percent !== undefined) updatePayload.y_percent = data.y_percent;
if (data.width_percent !== undefined) updatePayload.width_percent = data.width_percent;
if (data.height_percent !== undefined) updatePayload.height_percent = data.height_percent;
if (data.rotation_deg !== undefined) updatePayload.rotation_deg = data.rotation_deg;
if (data.style_json !== undefined) updatePayload.style_json = data.style_json;
if (data.content_json !== undefined) updatePayload.content_json = data.content_json;
updatePayload.updatedById = currentUser.id;
await page_elements.update(updatePayload, {transaction});
if (data.page !== undefined) {
await page_elements.setPage(
data.page,
{ transaction }
);
}
return page_elements;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const page_elements = await db.page_elements.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (transaction) => {
for (const record of page_elements) {
await record.update(
{deletedBy: currentUser.id},
{transaction}
);
}
for (const record of page_elements) {
await record.destroy({transaction});
}
});
return page_elements;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const page_elements = await db.page_elements.findByPk(id, options);
await page_elements.update({
deletedBy: currentUser.id
}, {
transaction,
});
await page_elements.destroy({
transaction
});
return page_elements;
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
static async findBy(where, options = {}) {
const transaction = options.transaction;
const runtimeEnvironment = getRuntimeEnvironment(options);
const runtimeProjectSlug = getRuntimeProjectSlug(options);
const pageInclude = {
@ -247,65 +80,28 @@ module.exports = class Page_elementsDBApi {
: [],
};
const page_elements = await db.page_elements.findOne(
{ where, include: [pageInclude], transaction },
);
if (!page_elements) {
return page_elements;
}
const output = page_elements.get({plain: true});
output.page = await page_elements.getPage({
transaction
const record = await this.MODEL.findOne({
where,
transaction,
include: [pageInclude],
});
return output;
if (!record) return null;
return record.get({ plain: true });
}
static async findAll(
filter,
options
) {
static async findAll(filter = {}, options = {}) {
filter = filter || {};
const limit = filter.limit || 0;
let offset = 0;
const currentPage = +filter.page || 0;
const offset = currentPage * limit;
let where = {};
const currentPage = +filter.page;
offset = currentPage * limit;
let include = [
{
model: db.tour_pages,
as: 'page',
where: filter.page ? {
[Op.or]: [
{ id: { [Op.in]: filter.page.split('|').map(term => Utils.uuid(term)) } },
@ -316,12 +112,9 @@ module.exports = class Page_elementsDBApi {
},
]
} : {},
},
];
const runtimeEnvironment = getRuntimeEnvironment(options);
const runtimeProjectSlug = getRuntimeProjectSlug(options);
@ -343,253 +136,48 @@ module.exports = class Page_elementsDBApi {
include[0].required = true;
}
if (filter) {
if (filter.id) {
where = {
...where,
['id']: Utils.uuid(filter.id),
};
where.id = Utils.uuid(filter.id);
}
if (filter.name) {
where = {
...where,
[Op.and]: Utils.ilike(
'page_elements',
'name',
filter.name,
),
};
for (const field of this.SEARCHABLE_FIELDS) {
if (filter[field]) {
where[Op.and] = Utils.ilike(this.TABLE_NAME, field, filter[field]);
}
}
if (filter.style_json) {
where = {
...where,
[Op.and]: Utils.ilike(
'page_elements',
'style_json',
filter.style_json,
),
};
}
if (filter.content_json) {
where = {
...where,
[Op.and]: Utils.ilike(
'page_elements',
'content_json',
filter.content_json,
),
};
}
if (filter.sort_orderRange) {
const [start, end] = filter.sort_orderRange;
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 = {
...where,
sort_order: {
...where.sort_order,
[Op.gte]: start,
},
};
where[field] = { ...where[field], [Op.gte]: start };
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
sort_order: {
...where.sort_order,
[Op.lte]: end,
},
};
where[field] = { ...where[field], [Op.lte]: end };
}
}
}
if (filter.x_percentRange) {
const [start, end] = filter.x_percentRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
x_percent: {
...where.x_percent,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
x_percent: {
...where.x_percent,
[Op.lte]: end,
},
};
for (const field of this.ENUM_FIELDS) {
if (filter[field] !== undefined) {
where[field] = filter[field];
}
}
if (filter.y_percentRange) {
const [start, end] = filter.y_percentRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
y_percent: {
...where.y_percent,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
y_percent: {
...where.y_percent,
[Op.lte]: end,
},
};
}
}
if (filter.width_percentRange) {
const [start, end] = filter.width_percentRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
width_percent: {
...where.width_percent,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
width_percent: {
...where.width_percent,
[Op.lte]: end,
},
};
}
}
if (filter.height_percentRange) {
const [start, end] = filter.height_percentRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
height_percent: {
...where.height_percent,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
height_percent: {
...where.height_percent,
[Op.lte]: end,
},
};
}
}
if (filter.rotation_degRange) {
const [start, end] = filter.rotation_degRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
rotation_deg: {
...where.rotation_deg,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
rotation_deg: {
...where.rotation_deg,
[Op.lte]: end,
},
};
}
}
if (filter.active !== undefined) {
where = {
...where,
active: filter.active === true || filter.active === 'true'
};
where.active = filter.active === true || filter.active === 'true';
}
if (filter.element_type) {
where = {
...where,
element_type: filter.element_type,
};
}
if (filter.is_visible) {
where = {
...where,
is_visible: filter.is_visible,
};
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.gte]: start,
},
};
where.createdAt = { ...where.createdAt, [Op.gte]: start };
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.lte]: end,
},
};
where.createdAt = { ...where.createdAt, [Op.lte]: end };
}
}
}
const queryOptions = {
where,
@ -598,59 +186,25 @@ module.exports = class Page_elementsDBApi {
order: filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log
transaction: options.transaction,
};
if (!options?.countOnly) {
if (!options.countOnly) {
queryOptions.limit = limit ? Number(limit) : undefined;
queryOptions.offset = offset ? Number(offset) : undefined;
}
try {
const { rows, count } = await db.page_elements.findAndCountAll(queryOptions);
const { rows, count } = await this.MODEL.findAndCountAll(queryOptions);
return {
rows: options?.countOnly ? [] : rows,
count: count
rows: options.countOnly ? [] : rows,
count,
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
static async findAllAutocomplete(query, limit, offset, ) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
Utils.ilike(
'page_elements',
'name',
query,
),
],
};
}
const records = await db.page_elements.findAll({
attributes: [ 'id', 'name' ],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
orderBy: [['name', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.name,
}));
}
};
module.exports = Page_elementsDBApi;

View File

@ -1,4 +1,4 @@
const GenericDBApi = require('./base.api');
const db = require('../models');
const Utils = require('../utils');
const {
@ -6,233 +6,58 @@ const {
getRuntimeProjectSlug,
} = require('./runtime-context');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class Page_linksDBApi {
class Page_linksDBApi extends GenericDBApi {
static get MODEL() {
return db.page_links;
}
static get TABLE_NAME() {
return 'page_links';
}
static get SEARCHABLE_FIELDS() {
return ['external_url', 'trigger_selector'];
}
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
static get RANGE_FIELDS() {
return [];
}
const page_links = await db.page_links.create(
{
static get ENUM_FIELDS() {
return ['direction', 'is_active'];
}
static get CSV_FIELDS() {
return ['id', 'direction', 'external_url', 'is_active', 'trigger_selector', 'createdAt'];
}
static get AUTOCOMPLETE_FIELD() {
return 'direction';
}
static get ASSOCIATIONS() {
return [
{ field: 'from_page', setter: 'setFrom_page', isArray: false },
{ field: 'to_page', setter: 'setTo_page', isArray: false },
{ field: 'transition', setter: 'setTransition', isArray: false },
];
}
static getFieldMapping(data) {
return {
id: data.id || undefined,
direction: data.direction
||
null
,
external_url: data.external_url
||
null
,
is_active: data.is_active
||
false
,
trigger_selector: data.trigger_selector
||
null
,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
await page_links.setFrom_page( data.from_page || null, {
transaction,
});
await page_links.setTo_page( data.to_page || null, {
transaction,
});
await page_links.setTransition( data.transition || null, {
transaction,
});
return page_links;
direction: data.direction || null,
external_url: data.external_url || null,
is_active: data.is_active || false,
trigger_selector: data.trigger_selector || null,
};
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
// Prepare data - wrapping individual data transformations in a map() method
const page_linksData = data.map((item, index) => ({
id: item.id || undefined,
direction: item.direction
||
null
,
external_url: item.external_url
||
null
,
is_active: item.is_active
||
false
,
trigger_selector: item.trigger_selector
||
null
,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const page_links = await db.page_links.bulkCreate(page_linksData, { transaction });
// For each item created, replace relation files
return page_links;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const page_links = await db.page_links.findByPk(id, {transaction});
const updatePayload = {};
if (data.direction !== undefined) updatePayload.direction = data.direction;
if (data.external_url !== undefined) updatePayload.external_url = data.external_url;
if (data.is_active !== undefined) updatePayload.is_active = data.is_active;
if (data.trigger_selector !== undefined) updatePayload.trigger_selector = data.trigger_selector;
updatePayload.updatedById = currentUser.id;
await page_links.update(updatePayload, {transaction});
if (data.from_page !== undefined) {
await page_links.setFrom_page(
data.from_page,
{ transaction }
);
}
if (data.to_page !== undefined) {
await page_links.setTo_page(
data.to_page,
{ transaction }
);
}
if (data.transition !== undefined) {
await page_links.setTransition(
data.transition,
{ transaction }
);
}
return page_links;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const page_links = await db.page_links.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (transaction) => {
for (const record of page_links) {
await record.update(
{deletedBy: currentUser.id},
{transaction}
);
}
for (const record of page_links) {
await record.destroy({transaction});
}
});
return page_links;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const page_links = await db.page_links.findByPk(id, options);
await page_links.update({
deletedBy: currentUser.id
}, {
transaction,
});
await page_links.destroy({
transaction
});
return page_links;
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
static async findBy(where, options = {}) {
const transaction = options.transaction;
const runtimeEnvironment = getRuntimeEnvironment(options);
const runtimeProjectSlug = getRuntimeProjectSlug(options);
const buildProjectInclude = () => (
@ -246,9 +71,9 @@ module.exports = class Page_linksDBApi {
: []
);
const page_links = await db.page_links.findOne(
{
const record = await this.MODEL.findOne({
where,
transaction,
include: [
{
model: db.tour_pages,
@ -257,6 +82,13 @@ module.exports = class Page_linksDBApi {
where: runtimeEnvironment ? { environment: runtimeEnvironment } : {},
include: buildProjectInclude(),
},
{
model: db.tour_pages,
as: 'to_page',
required: false,
where: runtimeEnvironment ? { environment: runtimeEnvironment } : {},
include: buildProjectInclude(),
},
{
model: db.transitions,
as: 'transition',
@ -265,75 +97,24 @@ module.exports = class Page_linksDBApi {
include: buildProjectInclude(),
},
],
transaction,
},
);
});
if (!page_links) {
return page_links;
if (!record) return null;
return record.get({ plain: true });
}
const output = page_links.get({plain: true});
output.from_page = await page_links.getFrom_page({
transaction
});
output.to_page = await page_links.getTo_page({
transaction
});
output.transition = await page_links.getTransition({
transaction
});
return output;
}
static async findAll(
filter,
options
) {
static async findAll(filter = {}, options = {}) {
filter = filter || {};
const limit = filter.limit || 0;
let offset = 0;
const currentPage = +filter.page || 0;
const offset = currentPage * limit;
let where = {};
const currentPage = +filter.page;
offset = currentPage * limit;
let include = [
{
model: db.tour_pages,
as: 'from_page',
where: filter.from_page ? {
[Op.or]: [
{ id: { [Op.in]: filter.from_page.split('|').map(term => Utils.uuid(term)) } },
@ -344,13 +125,10 @@ module.exports = class Page_linksDBApi {
},
]
} : {},
},
{
model: db.tour_pages,
as: 'to_page',
where: filter.to_page ? {
[Op.or]: [
{ id: { [Op.in]: filter.to_page.split('|').map(term => Utils.uuid(term)) } },
@ -361,13 +139,10 @@ module.exports = class Page_linksDBApi {
},
]
} : {},
},
{
model: db.transitions,
as: 'transition',
where: filter.transition ? {
[Op.or]: [
{ id: { [Op.in]: filter.transition.split('|').map(term => Utils.uuid(term)) } },
@ -378,151 +153,63 @@ module.exports = class Page_linksDBApi {
},
]
} : {},
},
];
const runtimeEnvironment = getRuntimeEnvironment(options);
const runtimeProjectSlug = getRuntimeProjectSlug(options);
if (runtimeEnvironment) {
include[0].where = {
...(include[0].where || {}),
environment: runtimeEnvironment,
};
include[0].where = { ...(include[0].where || {}), environment: runtimeEnvironment };
include[0].required = true;
include[1].where = {
...(include[1].where || {}),
environment: runtimeEnvironment,
};
include[2].where = {
...(include[2].where || {}),
environment: runtimeEnvironment,
};
include[1].where = { ...(include[1].where || {}), environment: runtimeEnvironment };
include[2].where = { ...(include[2].where || {}), environment: runtimeEnvironment };
include[2].required = false;
}
if (runtimeProjectSlug) {
include[0].include = [{
const projectInclude = [{
model: db.projects,
as: 'project',
required: true,
where: { slug: runtimeProjectSlug },
}];
include[0].include = projectInclude;
include[0].required = true;
include[1].include = [{
model: db.projects,
as: 'project',
required: true,
where: { slug: runtimeProjectSlug },
}];
include[2].include = [{
model: db.projects,
as: 'project',
required: true,
where: { slug: runtimeProjectSlug },
}];
include[1].include = projectInclude;
include[2].include = projectInclude;
include[2].required = false;
}
if (filter) {
if (filter.id) {
where = {
...where,
['id']: Utils.uuid(filter.id),
};
where.id = Utils.uuid(filter.id);
}
if (filter.external_url) {
where = {
...where,
[Op.and]: Utils.ilike(
'page_links',
'external_url',
filter.external_url,
),
};
for (const field of this.SEARCHABLE_FIELDS) {
if (filter[field]) {
where[Op.and] = Utils.ilike(this.TABLE_NAME, field, filter[field]);
}
}
if (filter.trigger_selector) {
where = {
...where,
[Op.and]: Utils.ilike(
'page_links',
'trigger_selector',
filter.trigger_selector,
),
};
for (const field of this.ENUM_FIELDS) {
if (filter[field] !== undefined) {
where[field] = filter[field];
}
}
if (filter.active !== undefined) {
where = {
...where,
active: filter.active === true || filter.active === 'true'
};
where.active = filter.active === true || filter.active === 'true';
}
if (filter.direction) {
where = {
...where,
direction: filter.direction,
};
}
if (filter.is_active) {
where = {
...where,
is_active: filter.is_active,
};
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.gte]: start,
},
};
where.createdAt = { ...where.createdAt, [Op.gte]: start };
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.lte]: end,
},
};
where.createdAt = { ...where.createdAt, [Op.lte]: end };
}
}
}
const queryOptions = {
where,
@ -531,59 +218,25 @@ module.exports = class Page_linksDBApi {
order: filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log
transaction: options.transaction,
};
if (!options?.countOnly) {
if (!options.countOnly) {
queryOptions.limit = limit ? Number(limit) : undefined;
queryOptions.offset = offset ? Number(offset) : undefined;
}
try {
const { rows, count } = await db.page_links.findAndCountAll(queryOptions);
const { rows, count } = await this.MODEL.findAndCountAll(queryOptions);
return {
rows: options?.countOnly ? [] : rows,
count: count
rows: options.countOnly ? [] : rows,
count,
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
static async findAllAutocomplete(query, limit, offset, ) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
Utils.ilike(
'page_links',
'direction',
query,
),
],
};
}
const records = await db.page_links.findAll({
attributes: [ 'id', 'direction' ],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
orderBy: [['direction', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.direction,
}));
}
};
module.exports = Page_linksDBApi;

View File

@ -1,335 +1,53 @@
const GenericDBApi = require('./base.api');
const db = require('../models');
const Utils = require('../utils');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class PermissionsDBApi {
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const permissions = await db.permissions.create(
{
id: data.id || undefined,
name: data.name
||
null
,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
return permissions;
class PermissionsDBApi extends GenericDBApi {
static get MODEL() {
return db.permissions;
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
// Prepare data - wrapping individual data transformations in a map() method
const permissionsData = data.map((item, index) => ({
id: item.id || undefined,
name: item.name
||
null
,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const permissions = await db.permissions.bulkCreate(permissionsData, { transaction });
// For each item created, replace relation files
return permissions;
static get TABLE_NAME() {
return 'permissions';
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const permissions = await db.permissions.findByPk(id, {transaction});
const updatePayload = {};
if (data.name !== undefined) updatePayload.name = data.name;
updatePayload.updatedById = currentUser.id;
await permissions.update(updatePayload, {transaction});
return permissions;
static get SEARCHABLE_FIELDS() {
return ['name'];
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const permissions = await db.permissions.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (transaction) => {
for (const record of permissions) {
await record.update(
{deletedBy: currentUser.id},
{transaction}
);
}
for (const record of permissions) {
await record.destroy({transaction});
}
});
return permissions;
static get RANGE_FIELDS() {
return [];
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const permissions = await db.permissions.findByPk(id, options);
await permissions.update({
deletedBy: currentUser.id
}, {
transaction,
});
await permissions.destroy({
transaction
});
return permissions;
static get ENUM_FIELDS() {
return [];
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
const permissions = await db.permissions.findOne({
where,
transaction,
});
if (!permissions) {
return permissions;
static get CSV_FIELDS() {
return ['id', 'name', 'createdAt'];
}
const output = permissions.get({plain: true});
return output;
static get AUTOCOMPLETE_FIELD() {
return 'name';
}
static async findAll(
filter,
options
) {
const limit = filter.limit || 0;
let offset = 0;
let where = {};
const currentPage = +filter.page;
offset = currentPage * limit;
let include = [
];
if (filter) {
if (filter.id) {
where = {
...where,
['id']: Utils.uuid(filter.id),
};
static get ASSOCIATIONS() {
return [];
}
if (filter.name) {
where = {
...where,
[Op.and]: Utils.ilike(
'permissions',
'name',
filter.name,
),
};
static get FIND_BY_INCLUDES() {
return [];
}
if (filter.active !== undefined) {
where = {
...where,
active: filter.active === true || filter.active === 'true'
};
static get FIND_ALL_INCLUDES() {
return [];
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.lte]: end,
},
};
}
}
}
const queryOptions = {
where,
include,
distinct: true,
order: filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log
};
if (!options?.countOnly) {
queryOptions.limit = limit ? Number(limit) : undefined;
queryOptions.offset = offset ? Number(offset) : undefined;
}
try {
const { rows, count } = await db.permissions.findAndCountAll(queryOptions);
static getFieldMapping(data) {
return {
rows: options?.countOnly ? [] : rows,
count: count
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
static async findAllAutocomplete(query, limit, offset, ) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
Utils.ilike(
'permissions',
'name',
query,
),
],
id: data.id || undefined,
name: data.name || null,
};
}
const records = await db.permissions.findAll({
attributes: [ 'id', 'name' ],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
orderBy: [['name', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.name,
}));
}
};
module.exports = PermissionsDBApi;

View File

@ -1,323 +1,78 @@
const GenericDBApi = require('./base.api');
const db = require('../models');
const Utils = require('../utils');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class Presigned_url_requestsDBApi {
class Presigned_url_requestsDBApi extends GenericDBApi {
static get MODEL() {
return db.presigned_url_requests;
}
static get TABLE_NAME() {
return 'presigned_url_requests';
}
static get SEARCHABLE_FIELDS() {
return ['requested_key', 'mime_type', 'status'];
}
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
static get RANGE_FIELDS() {
return ['requested_size_mb', 'expires_at'];
}
const presigned_url_requests = await db.presigned_url_requests.create(
{
static get ENUM_FIELDS() {
return ['purpose', 'asset_type'];
}
static get CSV_FIELDS() {
return ['id', 'purpose', 'asset_type', 'requested_key', 'mime_type', 'status', 'createdAt'];
}
static get AUTOCOMPLETE_FIELD() {
return 'requested_key';
}
static get ASSOCIATIONS() {
return [
{ field: 'project', setter: 'setProject', isArray: false },
{ field: 'user', setter: 'setUser', isArray: false },
];
}
static get FIND_BY_INCLUDES() {
return [
{ association: 'project' },
{ association: 'user' },
];
}
static getFieldMapping(data) {
return {
id: data.id || undefined,
purpose: data.purpose
||
null
,
asset_type: data.asset_type
||
null
,
requested_key: data.requested_key
||
null
,
mime_type: data.mime_type
||
null
,
requested_size_mb: data.requested_size_mb
||
null
,
expires_at: data.expires_at
||
null
,
status: data.status
||
null
,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
await presigned_url_requests.setProject( data.project || null, {
transaction,
});
await presigned_url_requests.setUser( data.user || null, {
transaction,
});
return presigned_url_requests;
purpose: data.purpose || null,
asset_type: data.asset_type || null,
requested_key: data.requested_key || null,
mime_type: data.mime_type || null,
requested_size_mb: data.requested_size_mb || null,
expires_at: data.expires_at || null,
status: data.status || null,
};
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
// Prepare data - wrapping individual data transformations in a map() method
const presigned_url_requestsData = data.map((item, index) => ({
id: item.id || undefined,
purpose: item.purpose
||
null
,
asset_type: item.asset_type
||
null
,
requested_key: item.requested_key
||
null
,
mime_type: item.mime_type
||
null
,
requested_size_mb: item.requested_size_mb
||
null
,
expires_at: item.expires_at
||
null
,
status: item.status
||
null
,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const presigned_url_requests = await db.presigned_url_requests.bulkCreate(presigned_url_requestsData, { transaction });
// For each item created, replace relation files
return presigned_url_requests;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const presigned_url_requests = await db.presigned_url_requests.findByPk(id, {transaction});
const updatePayload = {};
if (data.purpose !== undefined) updatePayload.purpose = data.purpose;
if (data.asset_type !== undefined) updatePayload.asset_type = data.asset_type;
if (data.requested_key !== undefined) updatePayload.requested_key = data.requested_key;
if (data.mime_type !== undefined) updatePayload.mime_type = data.mime_type;
if (data.requested_size_mb !== undefined) updatePayload.requested_size_mb = data.requested_size_mb;
if (data.expires_at !== undefined) updatePayload.expires_at = data.expires_at;
if (data.status !== undefined) updatePayload.status = data.status;
updatePayload.updatedById = currentUser.id;
await presigned_url_requests.update(updatePayload, {transaction});
if (data.project !== undefined) {
await presigned_url_requests.setProject(
data.project,
{ transaction }
);
}
if (data.user !== undefined) {
await presigned_url_requests.setUser(
data.user,
{ transaction }
);
}
return presigned_url_requests;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const presigned_url_requests = await db.presigned_url_requests.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (transaction) => {
for (const record of presigned_url_requests) {
await record.update(
{deletedBy: currentUser.id},
{transaction}
);
}
for (const record of presigned_url_requests) {
await record.destroy({transaction});
}
});
return presigned_url_requests;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const presigned_url_requests = await db.presigned_url_requests.findByPk(id, options);
await presigned_url_requests.update({
deletedBy: currentUser.id
}, {
transaction,
});
await presigned_url_requests.destroy({
transaction
});
return presigned_url_requests;
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
const presigned_url_requests = await db.presigned_url_requests.findOne({
where,
transaction,
});
if (!presigned_url_requests) {
return presigned_url_requests;
}
const output = presigned_url_requests.get({plain: true});
output.project = await presigned_url_requests.getProject({
transaction
});
output.user = await presigned_url_requests.getUser({
transaction
});
return output;
}
static async findAll(
filter,
options
) {
static async findAll(filter = {}, options = {}) {
filter = filter || {};
const limit = filter.limit || 0;
let offset = 0;
const currentPage = +filter.page || 0;
const offset = currentPage * limit;
let where = {};
const currentPage = +filter.page;
offset = currentPage * limit;
let include = [
{
model: db.projects,
as: 'project',
where: filter.project ? {
[Op.or]: [
{ id: { [Op.in]: filter.project.split('|').map(term => Utils.uuid(term)) } },
@ -328,13 +83,10 @@ module.exports = class Presigned_url_requestsDBApi {
},
]
} : {},
},
{
model: db.users,
as: 'user',
where: filter.user ? {
[Op.or]: [
{ id: { [Op.in]: filter.user.split('|').map(term => Utils.uuid(term)) } },
@ -345,166 +97,51 @@ module.exports = class Presigned_url_requestsDBApi {
},
]
} : {},
},
];
if (filter) {
if (filter.id) {
where = {
...where,
['id']: Utils.uuid(filter.id),
};
where.id = Utils.uuid(filter.id);
}
if (filter.requested_key) {
where = {
...where,
[Op.and]: Utils.ilike(
'presigned_url_requests',
'requested_key',
filter.requested_key,
),
};
for (const field of this.SEARCHABLE_FIELDS) {
if (filter[field]) {
where[Op.and] = Utils.ilike(this.TABLE_NAME, field, filter[field]);
}
}
if (filter.mime_type) {
where = {
...where,
[Op.and]: Utils.ilike(
'presigned_url_requests',
'mime_type',
filter.mime_type,
),
};
}
if (filter.status) {
where = {
...where,
[Op.and]: Utils.ilike(
'presigned_url_requests',
'status',
filter.status,
),
};
}
if (filter.requested_size_mbRange) {
const [start, end] = filter.requested_size_mbRange;
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 = {
...where,
requested_size_mb: {
...where.requested_size_mb,
[Op.gte]: start,
},
};
where[field] = { ...where[field], [Op.gte]: start };
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
requested_size_mb: {
...where.requested_size_mb,
[Op.lte]: end,
},
};
where[field] = { ...where[field], [Op.lte]: end };
}
}
}
if (filter.expires_atRange) {
const [start, end] = filter.expires_atRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
expires_at: {
...where.expires_at,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
expires_at: {
...where.expires_at,
[Op.lte]: end,
},
};
for (const field of this.ENUM_FIELDS) {
if (filter[field] !== undefined) {
where[field] = filter[field];
}
}
if (filter.active !== undefined) {
where = {
...where,
active: filter.active === true || filter.active === 'true'
};
where.active = filter.active === true || filter.active === 'true';
}
if (filter.purpose) {
where = {
...where,
purpose: filter.purpose,
};
}
if (filter.asset_type) {
where = {
...where,
asset_type: filter.asset_type,
};
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.gte]: start,
},
};
where.createdAt = { ...where.createdAt, [Op.gte]: start };
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.lte]: end,
},
};
where.createdAt = { ...where.createdAt, [Op.lte]: end };
}
}
}
const queryOptions = {
where,
@ -513,59 +150,25 @@ module.exports = class Presigned_url_requestsDBApi {
order: filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log
transaction: options.transaction,
};
if (!options?.countOnly) {
if (!options.countOnly) {
queryOptions.limit = limit ? Number(limit) : undefined;
queryOptions.offset = offset ? Number(offset) : undefined;
}
try {
const { rows, count } = await db.presigned_url_requests.findAndCountAll(queryOptions);
const { rows, count } = await this.MODEL.findAndCountAll(queryOptions);
return {
rows: options?.countOnly ? [] : rows,
count: count
rows: options.countOnly ? [] : rows,
count,
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
static async findAllAutocomplete(query, limit, offset, ) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
Utils.ilike(
'presigned_url_requests',
'requested_key',
query,
),
],
};
}
const records = await db.presigned_url_requests.findAll({
attributes: [ 'id', 'requested_key' ],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
orderBy: [['requested_key', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.requested_key,
}));
}
};
module.exports = Presigned_url_requestsDBApi;

View File

@ -1,4 +1,4 @@
const GenericDBApi = require('./base.api');
const db = require('../models');
const Utils = require('../utils');
const {
@ -6,342 +6,89 @@ const {
applyRuntimeProjectFilter,
} = require('./runtime-context');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class Project_audio_tracksDBApi {
class Project_audio_tracksDBApi extends GenericDBApi {
static get MODEL() {
return db.project_audio_tracks;
}
static get TABLE_NAME() {
return 'project_audio_tracks';
}
static get SEARCHABLE_FIELDS() {
return ['source_key', 'name', 'slug', 'url'];
}
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
static get RANGE_FIELDS() {
return ['volume', 'sort_order'];
}
const project_audio_tracks = await db.project_audio_tracks.create(
{
static get ENUM_FIELDS() {
return ['environment', 'loop', 'is_enabled'];
}
static get CSV_FIELDS() {
return ['id', 'environment', 'source_key', 'name', 'slug', 'url', 'loop', 'volume', 'createdAt'];
}
static get AUTOCOMPLETE_FIELD() {
return 'name';
}
static get ASSOCIATIONS() {
return [
{ field: 'project', setter: 'setProject', isArray: false },
];
}
static getFieldMapping(data) {
return {
id: data.id || undefined,
environment: data.environment
||
null
,
source_key: data.source_key
||
null
,
name: data.name
||
null
,
slug: data.slug
||
null
,
url: data.url
||
null
,
loop: data.loop
||
false
,
volume: data.volume
||
null
,
sort_order: data.sort_order
||
null
,
is_enabled: data.is_enabled
||
false
,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
await project_audio_tracks.setProject( data.project || null, {
transaction,
});
return project_audio_tracks;
environment: data.environment || null,
source_key: data.source_key || null,
name: data.name || null,
slug: data.slug || null,
url: data.url || null,
loop: data.loop || false,
volume: data.volume || null,
sort_order: data.sort_order || null,
is_enabled: data.is_enabled || false,
};
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
// Prepare data - wrapping individual data transformations in a map() method
const project_audio_tracksData = data.map((item, index) => ({
id: item.id || undefined,
environment: item.environment
||
null
,
source_key: item.source_key
||
null
,
name: item.name
||
null
,
slug: item.slug
||
null
,
url: item.url
||
null
,
loop: item.loop
||
false
,
volume: item.volume
||
null
,
sort_order: item.sort_order
||
null
,
is_enabled: item.is_enabled
||
false
,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const project_audio_tracks = await db.project_audio_tracks.bulkCreate(project_audio_tracksData, { transaction });
// For each item created, replace relation files
return project_audio_tracks;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const project_audio_tracks = await db.project_audio_tracks.findByPk(id, {transaction});
const updatePayload = {};
if (data.environment !== undefined) updatePayload.environment = data.environment;
if (data.source_key !== undefined) updatePayload.source_key = data.source_key;
if (data.name !== undefined) updatePayload.name = data.name;
if (data.slug !== undefined) updatePayload.slug = data.slug;
if (data.url !== undefined) updatePayload.url = data.url;
if (data.loop !== undefined) updatePayload.loop = data.loop;
if (data.volume !== undefined) updatePayload.volume = data.volume;
if (data.sort_order !== undefined) updatePayload.sort_order = data.sort_order;
if (data.is_enabled !== undefined) updatePayload.is_enabled = data.is_enabled;
updatePayload.updatedById = currentUser.id;
await project_audio_tracks.update(updatePayload, {transaction});
if (data.project !== undefined) {
await project_audio_tracks.setProject(
data.project,
{ transaction }
);
}
return project_audio_tracks;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const project_audio_tracks = await db.project_audio_tracks.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (transaction) => {
for (const record of project_audio_tracks) {
await record.update(
{deletedBy: currentUser.id},
{transaction}
);
}
for (const record of project_audio_tracks) {
await record.destroy({transaction});
}
});
return project_audio_tracks;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const project_audio_tracks = await db.project_audio_tracks.findByPk(id, options);
await project_audio_tracks.update({
deletedBy: currentUser.id
}, {
transaction,
});
await project_audio_tracks.destroy({
transaction
});
return project_audio_tracks;
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
static async findBy(where, options = {}) {
const transaction = options.transaction;
const queryWhere = applyRuntimeEnvironment({ ...where }, options);
const projectInclude = applyRuntimeProjectFilter(
{
model: db.projects,
as: 'project',
},
options,
{ model: db.projects, as: 'project' },
options
);
const project_audio_tracks = await db.project_audio_tracks.findOne(
{ where: queryWhere, include: [projectInclude], transaction },
);
if (!project_audio_tracks) {
return project_audio_tracks;
}
const output = project_audio_tracks.get({plain: true});
output.project = await project_audio_tracks.getProject({
transaction
const record = await this.MODEL.findOne({
where: queryWhere,
transaction,
include: [projectInclude],
});
return output;
if (!record) return null;
return record.get({ plain: true });
}
static async findAll(
filter,
options
) {
static async findAll(filter = {}, options = {}) {
filter = filter || {};
const limit = filter.limit || 0;
let offset = 0;
const currentPage = +filter.page || 0;
const offset = currentPage * limit;
let where = {};
const currentPage = +filter.page;
offset = currentPage * limit;
let include = [
{
model: db.projects,
as: 'project',
where: filter.project ? {
[Op.or]: [
{ id: { [Op.in]: filter.project.split('|').map(term => Utils.uuid(term)) } },
@ -352,185 +99,56 @@ module.exports = class Project_audio_tracksDBApi {
},
]
} : {},
},
];
include[0] = applyRuntimeProjectFilter(include[0], options);
if (filter) {
if (filter.id) {
where = {
...where,
['id']: Utils.uuid(filter.id),
};
where.id = Utils.uuid(filter.id);
}
if (filter.source_key) {
where = {
...where,
[Op.and]: Utils.ilike(
'project_audio_tracks',
'source_key',
filter.source_key,
),
};
for (const field of this.SEARCHABLE_FIELDS) {
if (filter[field]) {
where[Op.and] = Utils.ilike(this.TABLE_NAME, field, filter[field]);
}
}
if (filter.name) {
where = {
...where,
[Op.and]: Utils.ilike(
'project_audio_tracks',
'name',
filter.name,
),
};
}
if (filter.slug) {
where = {
...where,
[Op.and]: Utils.ilike(
'project_audio_tracks',
'slug',
filter.slug,
),
};
}
if (filter.url) {
where = {
...where,
[Op.and]: Utils.ilike(
'project_audio_tracks',
'url',
filter.url,
),
};
}
if (filter.volumeRange) {
const [start, end] = filter.volumeRange;
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 = {
...where,
volume: {
...where.volume,
[Op.gte]: start,
},
};
where[field] = { ...where[field], [Op.gte]: start };
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
volume: {
...where.volume,
[Op.lte]: end,
},
};
where[field] = { ...where[field], [Op.lte]: end };
}
}
}
if (filter.sort_orderRange) {
const [start, end] = filter.sort_orderRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
sort_order: {
...where.sort_order,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
sort_order: {
...where.sort_order,
[Op.lte]: end,
},
};
for (const field of this.ENUM_FIELDS) {
if (filter[field] !== undefined) {
where[field] = filter[field];
}
}
if (filter.active !== undefined) {
where = {
...where,
active: filter.active === true || filter.active === 'true'
};
where.active = filter.active === true || filter.active === 'true';
}
if (filter.environment) {
where = {
...where,
environment: filter.environment,
};
}
if (filter.loop) {
where = {
...where,
loop: filter.loop,
};
}
if (filter.is_enabled) {
where = {
...where,
is_enabled: filter.is_enabled,
};
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.gte]: start,
},
};
where.createdAt = { ...where.createdAt, [Op.gte]: start };
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.lte]: end,
},
};
}
where.createdAt = { ...where.createdAt, [Op.lte]: end };
}
}
where = applyRuntimeEnvironment(where, options);
const queryOptions = {
where,
include,
@ -538,59 +156,25 @@ module.exports = class Project_audio_tracksDBApi {
order: filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log
transaction: options.transaction,
};
if (!options?.countOnly) {
if (!options.countOnly) {
queryOptions.limit = limit ? Number(limit) : undefined;
queryOptions.offset = offset ? Number(offset) : undefined;
}
try {
const { rows, count } = await db.project_audio_tracks.findAndCountAll(queryOptions);
const { rows, count } = await this.MODEL.findAndCountAll(queryOptions);
return {
rows: options?.countOnly ? [] : rows,
count: count
rows: options.countOnly ? [] : rows,
count,
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
static async findAllAutocomplete(query, limit, offset, ) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
Utils.ilike(
'project_audio_tracks',
'name',
query,
),
],
};
}
const records = await db.project_audio_tracks.findAll({
attributes: [ 'id', 'name' ],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
orderBy: [['name', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.name,
}));
}
};
module.exports = Project_audio_tracksDBApi;

View File

@ -1,286 +1,75 @@
const GenericDBApi = require('./base.api');
const db = require('../models');
const Utils = require('../utils');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class Project_membershipsDBApi {
class Project_membershipsDBApi extends GenericDBApi {
static get MODEL() {
return db.project_memberships;
}
static get TABLE_NAME() {
return 'project_memberships';
}
static get SEARCHABLE_FIELDS() {
return [];
}
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
static get RANGE_FIELDS() {
return ['invited_at', 'accepted_at'];
}
const project_memberships = await db.project_memberships.create(
{
static get ENUM_FIELDS() {
return ['access_level', 'is_active'];
}
static get CSV_FIELDS() {
return ['id', 'access_level', 'is_active', 'invited_at', 'accepted_at', 'createdAt'];
}
static get AUTOCOMPLETE_FIELD() {
return 'access_level';
}
static get ASSOCIATIONS() {
return [
{ field: 'project', setter: 'setProject', isArray: false },
{ field: 'user', setter: 'setUser', isArray: false },
];
}
static get FIND_BY_INCLUDES() {
return [
{ association: 'project' },
{ association: 'user' },
];
}
static getFieldMapping(data) {
return {
id: data.id || undefined,
access_level: data.access_level
||
null
,
is_active: data.is_active
||
false
,
invited_at: data.invited_at
||
null
,
accepted_at: data.accepted_at
||
null
,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
await project_memberships.setProject( data.project || null, {
transaction,
});
await project_memberships.setUser( data.user || null, {
transaction,
});
return project_memberships;
access_level: data.access_level || null,
is_active: data.is_active || false,
invited_at: data.invited_at || null,
accepted_at: data.accepted_at || null,
};
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
// Prepare data - wrapping individual data transformations in a map() method
const project_membershipsData = data.map((item, index) => ({
id: item.id || undefined,
access_level: item.access_level
||
null
,
is_active: item.is_active
||
false
,
invited_at: item.invited_at
||
null
,
accepted_at: item.accepted_at
||
null
,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const project_memberships = await db.project_memberships.bulkCreate(project_membershipsData, { transaction });
// For each item created, replace relation files
return project_memberships;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const project_memberships = await db.project_memberships.findByPk(id, {transaction});
const updatePayload = {};
if (data.access_level !== undefined) updatePayload.access_level = data.access_level;
if (data.is_active !== undefined) updatePayload.is_active = data.is_active;
if (data.invited_at !== undefined) updatePayload.invited_at = data.invited_at;
if (data.accepted_at !== undefined) updatePayload.accepted_at = data.accepted_at;
updatePayload.updatedById = currentUser.id;
await project_memberships.update(updatePayload, {transaction});
if (data.project !== undefined) {
await project_memberships.setProject(
data.project,
{ transaction }
);
}
if (data.user !== undefined) {
await project_memberships.setUser(
data.user,
{ transaction }
);
}
return project_memberships;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const project_memberships = await db.project_memberships.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (transaction) => {
for (const record of project_memberships) {
await record.update(
{deletedBy: currentUser.id},
{transaction}
);
}
for (const record of project_memberships) {
await record.destroy({transaction});
}
});
return project_memberships;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const project_memberships = await db.project_memberships.findByPk(id, options);
await project_memberships.update({
deletedBy: currentUser.id
}, {
transaction,
});
await project_memberships.destroy({
transaction
});
return project_memberships;
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
const project_memberships = await db.project_memberships.findOne({
where,
transaction,
});
if (!project_memberships) {
return project_memberships;
}
const output = project_memberships.get({plain: true});
output.project = await project_memberships.getProject({
transaction
});
output.user = await project_memberships.getUser({
transaction
});
return output;
}
static async findAll(
filter,
options
) {
static async findAll(filter = {}, options = {}) {
filter = filter || {};
const limit = filter.limit || 0;
let offset = 0;
const currentPage = +filter.page || 0;
const offset = currentPage * limit;
let where = {};
const currentPage = +filter.page;
offset = currentPage * limit;
let include = [
{
model: db.projects,
as: 'project',
where: filter.project ? {
[Op.or]: [
{ id: { [Op.in]: filter.project.split('|').map(term => Utils.uuid(term)) } },
@ -291,13 +80,10 @@ module.exports = class Project_membershipsDBApi {
},
]
} : {},
},
{
model: db.users,
as: 'user',
where: filter.user ? {
[Op.or]: [
{ id: { [Op.in]: filter.user.split('|').map(term => Utils.uuid(term)) } },
@ -308,133 +94,45 @@ module.exports = class Project_membershipsDBApi {
},
]
} : {},
},
];
if (filter) {
if (filter.id) {
where = {
...where,
['id']: Utils.uuid(filter.id),
};
where.id = Utils.uuid(filter.id);
}
if (filter.invited_atRange) {
const [start, end] = filter.invited_atRange;
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 = {
...where,
invited_at: {
...where.invited_at,
[Op.gte]: start,
},
};
where[field] = { ...where[field], [Op.gte]: start };
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
invited_at: {
...where.invited_at,
[Op.lte]: end,
},
};
where[field] = { ...where[field], [Op.lte]: end };
}
}
}
if (filter.accepted_atRange) {
const [start, end] = filter.accepted_atRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
accepted_at: {
...where.accepted_at,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
accepted_at: {
...where.accepted_at,
[Op.lte]: end,
},
};
for (const field of this.ENUM_FIELDS) {
if (filter[field] !== undefined) {
where[field] = filter[field];
}
}
if (filter.active !== undefined) {
where = {
...where,
active: filter.active === true || filter.active === 'true'
};
where.active = filter.active === true || filter.active === 'true';
}
if (filter.access_level) {
where = {
...where,
access_level: filter.access_level,
};
}
if (filter.is_active) {
where = {
...where,
is_active: filter.is_active,
};
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.gte]: start,
},
};
where.createdAt = { ...where.createdAt, [Op.gte]: start };
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.lte]: end,
},
};
where.createdAt = { ...where.createdAt, [Op.lte]: end };
}
}
}
const queryOptions = {
where,
@ -443,59 +141,25 @@ module.exports = class Project_membershipsDBApi {
order: filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log
transaction: options.transaction,
};
if (!options?.countOnly) {
if (!options.countOnly) {
queryOptions.limit = limit ? Number(limit) : undefined;
queryOptions.offset = offset ? Number(offset) : undefined;
}
try {
const { rows, count } = await db.project_memberships.findAndCountAll(queryOptions);
const { rows, count } = await this.MODEL.findAndCountAll(queryOptions);
return {
rows: options?.countOnly ? [] : rows,
count: count
rows: options.countOnly ? [] : rows,
count,
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
static async findAllAutocomplete(query, limit, offset, ) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
Utils.ilike(
'project_memberships',
'access_level',
query,
),
],
};
}
const records = await db.project_memberships.findAll({
attributes: [ 'id', 'access_level' ],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
orderBy: [['access_level', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.access_level,
}));
}
};
module.exports = Project_membershipsDBApi;

View File

@ -1,4 +1,4 @@
const GenericDBApi = require('./base.api');
const db = require('../models');
const Utils = require('../utils');
const {
@ -6,311 +6,63 @@ const {
getRuntimeProjectSlug,
} = require('./runtime-context');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class ProjectsDBApi {
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', 'theme_config_json', 'custom_css_json', 'cdn_base_url', 'entry_page_slug'];
}
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
static get RANGE_FIELDS() {
return ['deleted_at_time'];
}
const projects = await db.projects.create(
{
static get ENUM_FIELDS() {
return ['phase', 'is_deleted'];
}
static get CSV_FIELDS() {
return ['id', 'name', 'slug', 'description', 'phase', 'logo_url', 'cdn_base_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
,
phase: data.phase
||
null
,
logo_url: data.logo_url
||
null
,
favicon_url: data.favicon_url
||
null
,
og_image_url: data.og_image_url
||
null
,
theme_config_json: data.theme_config_json
||
null
,
custom_css_json: data.custom_css_json
||
null
,
cdn_base_url: data.cdn_base_url
||
null
,
entry_page_slug: data.entry_page_slug
||
null
,
is_deleted: data.is_deleted
||
false
,
deleted_at_time: data.deleted_at_time
||
null
,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
return projects;
name: data.name || null,
slug: data.slug || null,
description: data.description || null,
phase: data.phase || null,
logo_url: data.logo_url || null,
favicon_url: data.favicon_url || null,
og_image_url: data.og_image_url || null,
theme_config_json: data.theme_config_json || null,
custom_css_json: data.custom_css_json || null,
cdn_base_url: data.cdn_base_url || null,
entry_page_slug: data.entry_page_slug || null,
is_deleted: data.is_deleted || false,
deleted_at_time: data.deleted_at_time || null,
};
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
// Prepare data - wrapping individual data transformations in a map() method
const projectsData = data.map((item, index) => ({
id: item.id || undefined,
name: item.name
||
null
,
slug: item.slug
||
null
,
description: item.description
||
null
,
phase: item.phase
||
null
,
logo_url: item.logo_url
||
null
,
favicon_url: item.favicon_url
||
null
,
og_image_url: item.og_image_url
||
null
,
theme_config_json: item.theme_config_json
||
null
,
custom_css_json: item.custom_css_json
||
null
,
cdn_base_url: item.cdn_base_url
||
null
,
entry_page_slug: item.entry_page_slug
||
null
,
is_deleted: item.is_deleted
||
false
,
deleted_at_time: item.deleted_at_time
||
null
,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const projects = await db.projects.bulkCreate(projectsData, { transaction });
// For each item created, replace relation files
return projects;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const projects = await db.projects.findByPk(id, {transaction});
const updatePayload = {};
if (data.name !== undefined) updatePayload.name = data.name;
if (data.slug !== undefined) updatePayload.slug = data.slug;
if (data.description !== undefined) updatePayload.description = data.description;
if (data.phase !== undefined) updatePayload.phase = data.phase;
if (data.logo_url !== undefined) updatePayload.logo_url = data.logo_url;
if (data.favicon_url !== undefined) updatePayload.favicon_url = data.favicon_url;
if (data.og_image_url !== undefined) updatePayload.og_image_url = data.og_image_url;
if (data.theme_config_json !== undefined) updatePayload.theme_config_json = data.theme_config_json;
if (data.custom_css_json !== undefined) updatePayload.custom_css_json = data.custom_css_json;
if (data.cdn_base_url !== undefined) updatePayload.cdn_base_url = data.cdn_base_url;
if (data.entry_page_slug !== undefined) updatePayload.entry_page_slug = data.entry_page_slug;
if (data.is_deleted !== undefined) updatePayload.is_deleted = data.is_deleted;
if (data.deleted_at_time !== undefined) updatePayload.deleted_at_time = data.deleted_at_time;
updatePayload.updatedById = currentUser.id;
await projects.update(updatePayload, {transaction});
return projects;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const projects = await db.projects.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (transaction) => {
for (const record of projects) {
await record.update(
{deletedBy: currentUser.id},
{transaction}
);
}
for (const record of projects) {
await record.destroy({transaction});
}
});
return projects;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const projects = await db.projects.findByPk(id, options);
await projects.update({
deletedBy: currentUser.id
}, {
transaction,
});
await projects.destroy({
transaction
});
return projects;
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
static async findBy(where, options = {}) {
const transaction = options.transaction;
const runtimeEnvironment = getRuntimeEnvironment(options);
const runtimeProjectSlug = getRuntimeProjectSlug(options);
const queryWhere = { ...where };
@ -325,315 +77,89 @@ module.exports = class ProjectsDBApi {
queryWhere.slug = runtimeProjectSlug;
}
const projects = await db.projects.findOne(
{ where: queryWhere, transaction },
);
const record = await this.MODEL.findOne({
where: queryWhere,
transaction,
include: [
{ association: 'project_memberships_project' },
{ association: 'assets_project' },
{ association: 'presigned_url_requests_project' },
{ association: 'tour_pages_project' },
{ association: 'transitions_project' },
{ association: 'project_audio_tracks_project' },
{ association: 'publish_events_project' },
{ association: 'pwa_caches_project' },
{ association: 'access_logs_project' },
],
});
if (!projects) {
return projects;
if (!record) return null;
return record.get({ plain: true });
}
const output = projects.get({plain: true});
output.project_memberships_project = await projects.getProject_memberships_project({
transaction
});
output.assets_project = await projects.getAssets_project({
transaction
});
output.presigned_url_requests_project = await projects.getPresigned_url_requests_project({
transaction
});
output.tour_pages_project = await projects.getTour_pages_project({
transaction
});
output.transitions_project = await projects.getTransitions_project({
transaction
});
output.project_audio_tracks_project = await projects.getProject_audio_tracks_project({
transaction
});
output.publish_events_project = await projects.getPublish_events_project({
transaction
});
output.pwa_caches_project = await projects.getPwa_caches_project({
transaction
});
output.access_logs_project = await projects.getAccess_logs_project({
transaction
});
return output;
}
static async findAll(
filter,
options
) {
static async findAll(filter = {}, options = {}) {
filter = filter || {};
const limit = filter.limit || 0;
let offset = 0;
const currentPage = +filter.page || 0;
const offset = currentPage * limit;
let where = {};
const currentPage = +filter.page;
let include = [];
offset = currentPage * limit;
let include = [
];
if (filter) {
if (filter.id) {
where = {
...where,
['id']: Utils.uuid(filter.id),
};
where.id = Utils.uuid(filter.id);
}
if (filter.name) {
where = {
...where,
[Op.and]: Utils.ilike(
'projects',
'name',
filter.name,
),
};
for (const field of this.SEARCHABLE_FIELDS) {
if (filter[field]) {
where[Op.and] = Utils.ilike(this.TABLE_NAME, field, filter[field]);
}
}
if (filter.slug) {
where = {
...where,
[Op.and]: Utils.ilike(
'projects',
'slug',
filter.slug,
),
};
}
if (filter.description) {
where = {
...where,
[Op.and]: Utils.ilike(
'projects',
'description',
filter.description,
),
};
}
if (filter.logo_url) {
where = {
...where,
[Op.and]: Utils.ilike(
'projects',
'logo_url',
filter.logo_url,
),
};
}
if (filter.favicon_url) {
where = {
...where,
[Op.and]: Utils.ilike(
'projects',
'favicon_url',
filter.favicon_url,
),
};
}
if (filter.og_image_url) {
where = {
...where,
[Op.and]: Utils.ilike(
'projects',
'og_image_url',
filter.og_image_url,
),
};
}
if (filter.theme_config_json) {
where = {
...where,
[Op.and]: Utils.ilike(
'projects',
'theme_config_json',
filter.theme_config_json,
),
};
}
if (filter.custom_css_json) {
where = {
...where,
[Op.and]: Utils.ilike(
'projects',
'custom_css_json',
filter.custom_css_json,
),
};
}
if (filter.cdn_base_url) {
where = {
...where,
[Op.and]: Utils.ilike(
'projects',
'cdn_base_url',
filter.cdn_base_url,
),
};
}
if (filter.entry_page_slug) {
where = {
...where,
[Op.and]: Utils.ilike(
'projects',
'entry_page_slug',
filter.entry_page_slug,
),
};
}
if (filter.deleted_at_timeRange) {
const [start, end] = filter.deleted_at_timeRange;
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 = {
...where,
deleted_at_time: {
...where.deleted_at_time,
[Op.gte]: start,
},
};
where[field] = { ...where[field], [Op.gte]: start };
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
deleted_at_time: {
...where.deleted_at_time,
[Op.lte]: 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 = {
...where,
active: filter.active === true || filter.active === 'true'
};
where.active = filter.active === true || filter.active === 'true';
}
if (filter.phase) {
where = {
...where,
phase: filter.phase,
};
}
if (filter.is_deleted) {
where = {
...where,
is_deleted: filter.is_deleted,
};
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.gte]: start,
},
};
where.createdAt = { ...where.createdAt, [Op.gte]: start };
}
if (end !== undefined && end !== null && end !== '') {
where.createdAt = { ...where.createdAt, [Op.lte]: end };
}
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.lte]: end,
},
};
}
}
}
const runtimeEnvironment = getRuntimeEnvironment(options);
const runtimeProjectSlug = getRuntimeProjectSlug(options);
if (runtimeEnvironment) {
where = {
...where,
phase: runtimeEnvironment,
};
where.phase = runtimeEnvironment;
}
if (runtimeProjectSlug) {
where = {
...where,
slug: runtimeProjectSlug,
};
where.slug = runtimeProjectSlug;
}
const queryOptions = {
where,
include,
@ -641,59 +167,25 @@ module.exports = class ProjectsDBApi {
order: filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log
transaction: options.transaction,
};
if (!options?.countOnly) {
if (!options.countOnly) {
queryOptions.limit = limit ? Number(limit) : undefined;
queryOptions.offset = offset ? Number(offset) : undefined;
}
try {
const { rows, count } = await db.projects.findAndCountAll(queryOptions);
const { rows, count } = await this.MODEL.findAndCountAll(queryOptions);
return {
rows: options?.countOnly ? [] : rows,
count: count
rows: options.countOnly ? [] : rows,
count,
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
static async findAllAutocomplete(query, limit, offset, ) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
Utils.ilike(
'projects',
'name',
query,
),
],
};
}
const records = await db.projects.findAll({
attributes: [ 'id', 'name' ],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
orderBy: [['name', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.name,
}));
}
};
module.exports = ProjectsDBApi;

View File

@ -1,375 +1,82 @@
const GenericDBApi = require('./base.api');
const db = require('../models');
const Utils = require('../utils');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class Publish_eventsDBApi {
class Publish_eventsDBApi extends GenericDBApi {
static get MODEL() {
return db.publish_events;
}
static get TABLE_NAME() {
return 'publish_events';
}
static get SEARCHABLE_FIELDS() {
return ['title', 'description', 'error_message'];
}
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
static get RANGE_FIELDS() {
return ['started_at', 'finished_at', 'pages_copied', 'transitions_copied', 'audios_copied'];
}
const publish_events = await db.publish_events.create(
{
static get ENUM_FIELDS() {
return ['from_environment', 'to_environment', 'status'];
}
static get CSV_FIELDS() {
return ['id', 'title', 'description', 'from_environment', 'to_environment', 'status', 'pages_copied', 'createdAt'];
}
static get AUTOCOMPLETE_FIELD() {
return 'status';
}
static get ASSOCIATIONS() {
return [
{ field: 'project', setter: 'setProject', isArray: false },
{ field: 'user', setter: 'setUser', isArray: false },
];
}
static get FIND_BY_INCLUDES() {
return [
{ association: 'project' },
{ association: 'user' },
];
}
static getFieldMapping(data) {
return {
id: data.id || undefined,
title: data.title
||
null
,
description: data.description
||
null
,
from_environment: data.from_environment
||
null
,
to_environment: data.to_environment
||
null
,
started_at: data.started_at
||
null
,
finished_at: data.finished_at
||
null
,
status: data.status
||
null
,
error_message: data.error_message
||
null
,
pages_copied: data.pages_copied
||
null
,
transitions_copied: data.transitions_copied
||
null
,
audios_copied: data.audios_copied
||
null
,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
await publish_events.setProject( data.project || null, {
transaction,
});
await publish_events.setUser( data.user || null, {
transaction,
});
return publish_events;
title: data.title || null,
description: data.description || null,
from_environment: data.from_environment || null,
to_environment: data.to_environment || null,
started_at: data.started_at || null,
finished_at: data.finished_at || null,
status: data.status || null,
error_message: data.error_message || null,
pages_copied: data.pages_copied || null,
transitions_copied: data.transitions_copied || null,
audios_copied: data.audios_copied || null,
};
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
// Prepare data - wrapping individual data transformations in a map() method
const publish_eventsData = data.map((item, index) => ({
id: item.id || undefined,
title: item.title
||
null
,
description: item.description
||
null
,
from_environment: item.from_environment
||
null
,
to_environment: item.to_environment
||
null
,
started_at: item.started_at
||
null
,
finished_at: item.finished_at
||
null
,
status: item.status
||
null
,
error_message: item.error_message
||
null
,
pages_copied: item.pages_copied
||
null
,
transitions_copied: item.transitions_copied
||
null
,
audios_copied: item.audios_copied
||
null
,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const publish_events = await db.publish_events.bulkCreate(publish_eventsData, { transaction });
// For each item created, replace relation files
return publish_events;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const publish_events = await db.publish_events.findByPk(id, {transaction});
const updatePayload = {};
if (data.title !== undefined) updatePayload.title = data.title;
if (data.description !== undefined) updatePayload.description = data.description;
if (data.from_environment !== undefined) updatePayload.from_environment = data.from_environment;
if (data.to_environment !== undefined) updatePayload.to_environment = data.to_environment;
if (data.started_at !== undefined) updatePayload.started_at = data.started_at;
if (data.finished_at !== undefined) updatePayload.finished_at = data.finished_at;
if (data.status !== undefined) updatePayload.status = data.status;
if (data.error_message !== undefined) updatePayload.error_message = data.error_message;
if (data.pages_copied !== undefined) updatePayload.pages_copied = data.pages_copied;
if (data.transitions_copied !== undefined) updatePayload.transitions_copied = data.transitions_copied;
if (data.audios_copied !== undefined) updatePayload.audios_copied = data.audios_copied;
updatePayload.updatedById = currentUser.id;
await publish_events.update(updatePayload, {transaction});
if (data.project !== undefined) {
await publish_events.setProject(
data.project,
{ transaction }
);
}
if (data.user !== undefined) {
await publish_events.setUser(
data.user,
{ transaction }
);
}
return publish_events;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const publish_events = await db.publish_events.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (transaction) => {
for (const record of publish_events) {
await record.update(
{deletedBy: currentUser.id},
{transaction}
);
}
for (const record of publish_events) {
await record.destroy({transaction});
}
});
return publish_events;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const publish_events = await db.publish_events.findByPk(id, options);
await publish_events.update({
deletedBy: currentUser.id
}, {
transaction,
});
await publish_events.destroy({
transaction
});
return publish_events;
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
const publish_events = await db.publish_events.findOne({
where,
transaction,
});
if (!publish_events) {
return publish_events;
}
const output = publish_events.get({plain: true});
output.project = await publish_events.getProject({
transaction
});
output.user = await publish_events.getUser({
transaction
});
return output;
}
static async findAll(
filter,
options
) {
static async findAll(filter = {}, options = {}) {
filter = filter || {};
const limit = filter.limit || 0;
let offset = 0;
const currentPage = +filter.page || 0;
const offset = currentPage * limit;
let where = {};
const currentPage = +filter.page;
offset = currentPage * limit;
let include = [
{
model: db.projects,
as: 'project',
where: filter.project ? {
[Op.or]: [
{ id: { [Op.in]: filter.project.split('|').map(term => Utils.uuid(term)) } },
@ -380,13 +87,10 @@ module.exports = class Publish_eventsDBApi {
},
]
} : {},
},
{
model: db.users,
as: 'user',
where: filter.user ? {
[Op.or]: [
{ id: { [Op.in]: filter.user.split('|').map(term => Utils.uuid(term)) } },
@ -397,246 +101,51 @@ module.exports = class Publish_eventsDBApi {
},
]
} : {},
},
];
if (filter) {
if (filter.id) {
where = {
...where,
['id']: Utils.uuid(filter.id),
};
where.id = Utils.uuid(filter.id);
}
if (filter.title) {
where = {
...where,
[Op.and]: Utils.ilike(
'publish_events',
'title',
filter.title,
),
};
for (const field of this.SEARCHABLE_FIELDS) {
if (filter[field]) {
where[Op.and] = Utils.ilike(this.TABLE_NAME, field, filter[field]);
}
}
if (filter.description) {
where = {
...where,
[Op.and]: Utils.ilike(
'publish_events',
'description',
filter.description,
),
};
}
if (filter.error_message) {
where = {
...where,
[Op.and]: Utils.ilike(
'publish_events',
'error_message',
filter.error_message,
),
};
}
if (filter.started_atRange) {
const [start, end] = filter.started_atRange;
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 = {
...where,
started_at: {
...where.started_at,
[Op.gte]: start,
},
};
where[field] = { ...where[field], [Op.gte]: start };
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
started_at: {
...where.started_at,
[Op.lte]: end,
},
};
where[field] = { ...where[field], [Op.lte]: end };
}
}
}
if (filter.finished_atRange) {
const [start, end] = filter.finished_atRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
finished_at: {
...where.finished_at,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
finished_at: {
...where.finished_at,
[Op.lte]: end,
},
};
for (const field of this.ENUM_FIELDS) {
if (filter[field] !== undefined) {
where[field] = filter[field];
}
}
if (filter.pages_copiedRange) {
const [start, end] = filter.pages_copiedRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
pages_copied: {
...where.pages_copied,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
pages_copied: {
...where.pages_copied,
[Op.lte]: end,
},
};
}
}
if (filter.transitions_copiedRange) {
const [start, end] = filter.transitions_copiedRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
transitions_copied: {
...where.transitions_copied,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
transitions_copied: {
...where.transitions_copied,
[Op.lte]: end,
},
};
}
}
if (filter.audios_copiedRange) {
const [start, end] = filter.audios_copiedRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
audios_copied: {
...where.audios_copied,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
audios_copied: {
...where.audios_copied,
[Op.lte]: end,
},
};
}
}
if (filter.active !== undefined) {
where = {
...where,
active: filter.active === true || filter.active === 'true'
};
where.active = filter.active === true || filter.active === 'true';
}
if (filter.from_environment) {
where = {
...where,
from_environment: filter.from_environment,
};
}
if (filter.to_environment) {
where = {
...where,
to_environment: filter.to_environment,
};
}
if (filter.status) {
where = {
...where,
status: filter.status,
};
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.gte]: start,
},
};
where.createdAt = { ...where.createdAt, [Op.gte]: start };
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.lte]: end,
},
};
where.createdAt = { ...where.createdAt, [Op.lte]: end };
}
}
}
const queryOptions = {
where,
@ -645,59 +154,25 @@ module.exports = class Publish_eventsDBApi {
order: filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log
transaction: options.transaction,
};
if (!options?.countOnly) {
if (!options.countOnly) {
queryOptions.limit = limit ? Number(limit) : undefined;
queryOptions.offset = offset ? Number(offset) : undefined;
}
try {
const { rows, count } = await db.publish_events.findAndCountAll(queryOptions);
const { rows, count } = await this.MODEL.findAndCountAll(queryOptions);
return {
rows: options?.countOnly ? [] : rows,
count: count
rows: options.countOnly ? [] : rows,
count,
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
static async findAllAutocomplete(query, limit, offset, ) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
Utils.ilike(
'publish_events',
'status',
query,
),
],
};
}
const records = await db.publish_events.findAll({
attributes: [ 'id', 'status' ],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
orderBy: [['status', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.status,
}));
}
};
module.exports = Publish_eventsDBApi;

View File

@ -1,294 +1,73 @@
const GenericDBApi = require('./base.api');
const db = require('../models');
const Utils = require('../utils');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class Pwa_cachesDBApi {
class Pwa_cachesDBApi extends GenericDBApi {
static get MODEL() {
return db.pwa_caches;
}
static get TABLE_NAME() {
return 'pwa_caches';
}
static get SEARCHABLE_FIELDS() {
return ['cache_version', 'manifest_json', 'asset_list_json'];
}
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
static get RANGE_FIELDS() {
return ['generated_at'];
}
const pwa_caches = await db.pwa_caches.create(
{
static get ENUM_FIELDS() {
return ['environment', 'is_active'];
}
static get CSV_FIELDS() {
return ['id', 'environment', 'cache_version', 'is_active', 'generated_at', 'createdAt'];
}
static get AUTOCOMPLETE_FIELD() {
return 'cache_version';
}
static get ASSOCIATIONS() {
return [
{ field: 'project', setter: 'setProject', isArray: false },
];
}
static get FIND_BY_INCLUDES() {
return [{ association: 'project' }];
}
static getFieldMapping(data) {
return {
id: data.id || undefined,
environment: data.environment
||
null
,
cache_version: data.cache_version
||
null
,
manifest_json: data.manifest_json
||
null
,
asset_list_json: data.asset_list_json
||
null
,
generated_at: data.generated_at
||
null
,
is_active: data.is_active
||
false
,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
await pwa_caches.setProject( data.project || null, {
transaction,
});
return pwa_caches;
environment: data.environment || null,
cache_version: data.cache_version || null,
manifest_json: data.manifest_json || null,
asset_list_json: data.asset_list_json || null,
generated_at: data.generated_at || null,
is_active: data.is_active || false,
};
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
// Prepare data - wrapping individual data transformations in a map() method
const pwa_cachesData = data.map((item, index) => ({
id: item.id || undefined,
environment: item.environment
||
null
,
cache_version: item.cache_version
||
null
,
manifest_json: item.manifest_json
||
null
,
asset_list_json: item.asset_list_json
||
null
,
generated_at: item.generated_at
||
null
,
is_active: item.is_active
||
false
,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const pwa_caches = await db.pwa_caches.bulkCreate(pwa_cachesData, { transaction });
// For each item created, replace relation files
return pwa_caches;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const pwa_caches = await db.pwa_caches.findByPk(id, {transaction});
const updatePayload = {};
if (data.environment !== undefined) updatePayload.environment = data.environment;
if (data.cache_version !== undefined) updatePayload.cache_version = data.cache_version;
if (data.manifest_json !== undefined) updatePayload.manifest_json = data.manifest_json;
if (data.asset_list_json !== undefined) updatePayload.asset_list_json = data.asset_list_json;
if (data.generated_at !== undefined) updatePayload.generated_at = data.generated_at;
if (data.is_active !== undefined) updatePayload.is_active = data.is_active;
updatePayload.updatedById = currentUser.id;
await pwa_caches.update(updatePayload, {transaction});
if (data.project !== undefined) {
await pwa_caches.setProject(
data.project,
{ transaction }
);
}
return pwa_caches;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const pwa_caches = await db.pwa_caches.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (transaction) => {
for (const record of pwa_caches) {
await record.update(
{deletedBy: currentUser.id},
{transaction}
);
}
for (const record of pwa_caches) {
await record.destroy({transaction});
}
});
return pwa_caches;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const pwa_caches = await db.pwa_caches.findByPk(id, options);
await pwa_caches.update({
deletedBy: currentUser.id
}, {
transaction,
});
await pwa_caches.destroy({
transaction
});
return pwa_caches;
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
const pwa_caches = await db.pwa_caches.findOne({
where,
transaction,
});
if (!pwa_caches) {
return pwa_caches;
}
const output = pwa_caches.get({plain: true});
output.project = await pwa_caches.getProject({
transaction
});
return output;
}
static async findAll(
filter,
options
) {
static async findAll(filter = {}, options = {}) {
filter = filter || {};
const limit = filter.limit || 0;
let offset = 0;
const currentPage = +filter.page || 0;
const offset = currentPage * limit;
let where = {};
const currentPage = +filter.page;
offset = currentPage * limit;
let include = [
{
model: db.projects,
as: 'project',
where: filter.project ? {
[Op.or]: [
{ id: { [Op.in]: filter.project.split('|').map(term => Utils.uuid(term)) } },
@ -299,140 +78,51 @@ module.exports = class Pwa_cachesDBApi {
},
]
} : {},
},
];
if (filter) {
if (filter.id) {
where = {
...where,
['id']: Utils.uuid(filter.id),
};
where.id = Utils.uuid(filter.id);
}
if (filter.cache_version) {
where = {
...where,
[Op.and]: Utils.ilike(
'pwa_caches',
'cache_version',
filter.cache_version,
),
};
for (const field of this.SEARCHABLE_FIELDS) {
if (filter[field]) {
where[Op.and] = Utils.ilike(this.TABLE_NAME, field, filter[field]);
}
}
if (filter.manifest_json) {
where = {
...where,
[Op.and]: Utils.ilike(
'pwa_caches',
'manifest_json',
filter.manifest_json,
),
};
}
if (filter.asset_list_json) {
where = {
...where,
[Op.and]: Utils.ilike(
'pwa_caches',
'asset_list_json',
filter.asset_list_json,
),
};
}
if (filter.generated_atRange) {
const [start, end] = filter.generated_atRange;
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 = {
...where,
generated_at: {
...where.generated_at,
[Op.gte]: start,
},
};
where[field] = { ...where[field], [Op.gte]: start };
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
generated_at: {
...where.generated_at,
[Op.lte]: 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 = {
...where,
active: filter.active === true || filter.active === 'true'
};
where.active = filter.active === true || filter.active === 'true';
}
if (filter.environment) {
where = {
...where,
environment: filter.environment,
};
}
if (filter.is_active) {
where = {
...where,
is_active: filter.is_active,
};
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.gte]: start,
},
};
where.createdAt = { ...where.createdAt, [Op.gte]: start };
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.lte]: end,
},
};
where.createdAt = { ...where.createdAt, [Op.lte]: end };
}
}
}
const queryOptions = {
where,
@ -441,59 +131,25 @@ module.exports = class Pwa_cachesDBApi {
order: filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log
transaction: options.transaction,
};
if (!options?.countOnly) {
if (!options.countOnly) {
queryOptions.limit = limit ? Number(limit) : undefined;
queryOptions.offset = offset ? Number(offset) : undefined;
}
try {
const { rows, count } = await db.pwa_caches.findAndCountAll(queryOptions);
const { rows, count } = await this.MODEL.findAndCountAll(queryOptions);
return {
rows: options?.countOnly ? [] : rows,
count: count
rows: options.countOnly ? [] : rows,
count,
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
static async findAllAutocomplete(query, limit, offset, ) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
Utils.ilike(
'pwa_caches',
'cache_version',
query,
),
],
};
}
const records = await db.pwa_caches.findAll({
attributes: [ 'id', 'cache_version' ],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
orderBy: [['cache_version', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.cache_version,
}));
}
};
module.exports = Pwa_cachesDBApi;

View File

@ -1,296 +1,92 @@
const GenericDBApi = require('./base.api');
const db = require('../models');
const Utils = require('../utils');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class RolesDBApi {
class RolesDBApi extends GenericDBApi {
static get MODEL() {
return db.roles;
}
static get TABLE_NAME() {
return 'roles';
}
static get SEARCHABLE_FIELDS() {
return ['name', 'role_customization'];
}
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
static get RANGE_FIELDS() {
return [];
}
const roles = await db.roles.create(
{
static get ENUM_FIELDS() {
return [];
}
static get CSV_FIELDS() {
return ['id', 'name', 'role_customization', 'createdAt'];
}
static get AUTOCOMPLETE_FIELD() {
return 'name';
}
static get ASSOCIATIONS() {
return [
{ field: 'permissions', setter: 'setPermissions', isArray: true },
];
}
static get FIND_BY_INCLUDES() {
return [
{ association: 'users_app_role' },
{ association: 'permissions' },
];
}
static getFieldMapping(data) {
return {
id: data.id || undefined,
name: data.name
||
null
,
role_customization: data.role_customization
||
null
,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
await roles.setPermissions(data.permissions || [], {
transaction,
});
return roles;
name: data.name || null,
role_customization: data.role_customization || null,
};
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
// Prepare data - wrapping individual data transformations in a map() method
const rolesData = data.map((item, index) => ({
id: item.id || undefined,
name: item.name
||
null
,
role_customization: item.role_customization
||
null
,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const roles = await db.roles.bulkCreate(rolesData, { transaction });
// For each item created, replace relation files
return roles;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const roles = await db.roles.findByPk(id, {transaction});
const updatePayload = {};
if (data.name !== undefined) updatePayload.name = data.name;
if (data.role_customization !== undefined) updatePayload.role_customization = data.role_customization;
updatePayload.updatedById = currentUser.id;
await roles.update(updatePayload, {transaction});
if (data.permissions !== undefined) {
await roles.setPermissions(data.permissions, { transaction });
}
return roles;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const roles = await db.roles.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (transaction) => {
for (const record of roles) {
await record.update(
{deletedBy: currentUser.id},
{transaction}
);
}
for (const record of roles) {
await record.destroy({transaction});
}
});
return roles;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const roles = await db.roles.findByPk(id, options);
await roles.update({
deletedBy: currentUser.id
}, {
transaction,
});
await roles.destroy({
transaction
});
return roles;
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
const roles = await db.roles.findOne({
where,
transaction,
});
if (!roles) {
return roles;
}
const output = roles.get({plain: true});
output.users_app_role = await roles.getUsers_app_role({
transaction
});
output.permissions = await roles.getPermissions({
transaction
});
return output;
}
static async findAll(
filter,
options
) {
static async findAll(filter = {}, options = {}) {
filter = filter || {};
const limit = filter.limit || 0;
let offset = 0;
const currentPage = +filter.page || 0;
const offset = currentPage * limit;
let where = {};
const currentPage = +filter.page;
offset = currentPage * limit;
let include = [
{
model: db.permissions,
as: 'permissions',
required: false,
},
];
if (filter) {
if (filter.id) {
where = {
...where,
['id']: Utils.uuid(filter.id),
};
where.id = Utils.uuid(filter.id);
}
if (filter.name) {
where = {
...where,
[Op.and]: Utils.ilike(
'roles',
'name',
filter.name,
),
};
for (const field of this.SEARCHABLE_FIELDS) {
if (filter[field]) {
where[Op.and] = Utils.ilike(this.TABLE_NAME, field, filter[field]);
}
if (filter.role_customization) {
where = {
...where,
[Op.and]: Utils.ilike(
'roles',
'role_customization',
filter.role_customization,
),
};
}
if (filter.active !== undefined) {
where = {
...where,
active: filter.active === true || filter.active === 'true'
};
where.active = filter.active === true || filter.active === 'true';
}
if (filter.permissions) {
const searchTerms = filter.permissions.split('|');
include = [
{
model: db.permissions,
@ -308,37 +104,18 @@ module.exports = class RolesDBApi {
} : undefined
},
...include,
]
];
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.gte]: start,
},
};
where.createdAt = { ...where.createdAt, [Op.gte]: start };
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.lte]: end,
},
};
where.createdAt = { ...where.createdAt, [Op.lte]: end };
}
}
}
const queryOptions = {
where,
@ -347,59 +124,25 @@ module.exports = class RolesDBApi {
order: filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log
transaction: options.transaction,
};
if (!options?.countOnly) {
if (!options.countOnly) {
queryOptions.limit = limit ? Number(limit) : undefined;
queryOptions.offset = offset ? Number(offset) : undefined;
}
try {
const { rows, count } = await db.roles.findAndCountAll(queryOptions);
const { rows, count } = await this.MODEL.findAndCountAll(queryOptions);
return {
rows: options?.countOnly ? [] : rows,
count: count
rows: options.countOnly ? [] : rows,
count,
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
static async findAllAutocomplete(query, limit, offset, ) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
Utils.ilike(
'roles',
'name',
query,
),
],
};
}
const records = await db.roles.findAll({
attributes: [ 'id', 'name' ],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
orderBy: [['name', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.name,
}));
}
};
module.exports = RolesDBApi;

View File

@ -1,4 +1,4 @@
const GenericDBApi = require('./base.api');
const db = require('../models');
const Utils = require('../utils');
const {
@ -6,302 +6,84 @@ const {
applyRuntimeProjectFilter,
} = require('./runtime-context');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class Tour_pagesDBApi {
class Tour_pagesDBApi extends GenericDBApi {
static get MODEL() {
return db.tour_pages;
}
static get TABLE_NAME() {
return 'tour_pages';
}
static get SEARCHABLE_FIELDS() {
return ['source_key', 'name', 'slug', 'background_image_url', 'background_video_url', 'background_audio_url', 'ui_schema_json'];
}
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
static get RANGE_FIELDS() {
return ['sort_order'];
}
static get ENUM_FIELDS() {
return ['environment', 'background_loop', 'requires_auth'];
}
static get CSV_FIELDS() {
return ['id', 'environment', 'source_key', 'name', 'slug', 'sort_order', 'createdAt'];
}
static get AUTOCOMPLETE_FIELD() {
return 'name';
}
static get ASSOCIATIONS() {
return [
{ field: 'project', setter: 'setProject', isArray: false },
];
}
static getFieldMapping(data) {
return {
id: data.id || undefined,
environment: data.environment || null,
source_key: data.source_key || null,
name: data.name || null,
slug: data.slug || null,
sort_order: data.sort_order || null,
background_image_url: data.background_image_url || null,
background_video_url: data.background_video_url || null,
background_audio_url: data.background_audio_url || null,
background_loop: data.background_loop || false,
requires_auth: data.requires_auth || false,
ui_schema_json: data.ui_schema_json || null,
};
}
static async create(data, options = {}) {
const currentUser = options.currentUser || { id: null };
const transaction = options.transaction;
const projectId = data.project || data.projectId || null;
const tour_pages = await db.tour_pages.create(
const record = await this.MODEL.create(
{
id: data.id || undefined,
environment: data.environment
||
null
,
source_key: data.source_key
||
null
,
name: data.name
||
null
,
slug: data.slug
||
null
,
sort_order: data.sort_order
||
null
,
background_image_url: data.background_image_url
||
null
,
background_video_url: data.background_video_url
||
null
,
background_audio_url: data.background_audio_url
||
null
,
background_loop: data.background_loop
||
false
,
requires_auth: data.requires_auth
||
false
,
ui_schema_json: data.ui_schema_json
||
null
,
...this.getFieldMapping(data),
projectId,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
await tour_pages.setProject(projectId, {
transaction,
});
return tour_pages;
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
// Prepare data - wrapping individual data transformations in a map() method
const tour_pagesData = data.map((item, index) => ({
id: item.id || undefined,
environment: item.environment
||
null
,
source_key: item.source_key
||
null
,
name: item.name
||
null
,
slug: item.slug
||
null
,
sort_order: item.sort_order
||
null
,
background_image_url: item.background_image_url
||
null
,
background_video_url: item.background_video_url
||
null
,
background_audio_url: item.background_audio_url
||
null
,
background_loop: item.background_loop
||
false
,
requires_auth: item.requires_auth
||
false
,
ui_schema_json: item.ui_schema_json
||
null
,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const tour_pages = await db.tour_pages.bulkCreate(tour_pagesData, { transaction });
// For each item created, replace relation files
return tour_pages;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const tour_pages = await db.tour_pages.findByPk(id, {transaction});
const updatePayload = {};
if (data.environment !== undefined) updatePayload.environment = data.environment;
if (data.source_key !== undefined) updatePayload.source_key = data.source_key;
if (data.name !== undefined) updatePayload.name = data.name;
if (data.slug !== undefined) updatePayload.slug = data.slug;
if (data.sort_order !== undefined) updatePayload.sort_order = data.sort_order;
if (data.background_image_url !== undefined) updatePayload.background_image_url = data.background_image_url;
if (data.background_video_url !== undefined) updatePayload.background_video_url = data.background_video_url;
if (data.background_audio_url !== undefined) updatePayload.background_audio_url = data.background_audio_url;
if (data.background_loop !== undefined) updatePayload.background_loop = data.background_loop;
if (data.requires_auth !== undefined) updatePayload.requires_auth = data.requires_auth;
if (data.ui_schema_json !== undefined) updatePayload.ui_schema_json = data.ui_schema_json;
updatePayload.updatedById = currentUser.id;
await tour_pages.update(updatePayload, {transaction});
if (data.project !== undefined) {
await tour_pages.setProject(
data.project,
{ transaction }
);
await record.setProject(projectId, { transaction });
return record;
}
return tour_pages;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const tour_pages = await db.tour_pages.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (transaction) => {
for (const record of tour_pages) {
await record.update(
{deletedBy: currentUser.id},
{transaction}
);
}
for (const record of tour_pages) {
await record.destroy({transaction});
}
});
return tour_pages;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const tour_pages = await db.tour_pages.findByPk(id, options);
await tour_pages.update({
deletedBy: currentUser.id
}, {
transaction,
});
await tour_pages.destroy({
transaction
});
return tour_pages;
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
static async findBy(where, options = {}) {
const transaction = options.transaction;
const queryWhere = applyRuntimeEnvironment({ ...where }, options);
const projectInclude = applyRuntimeProjectFilter(
{
@ -311,77 +93,33 @@ module.exports = class Tour_pagesDBApi {
options,
);
const tour_pages = await db.tour_pages.findOne(
{ where: queryWhere, include: [projectInclude], transaction },
);
const record = await this.MODEL.findOne({
where: queryWhere,
transaction,
include: [
projectInclude,
{ association: 'page_elements_page' },
{ association: 'page_links_from_page' },
{ association: 'page_links_to_page' },
],
});
if (!tour_pages) {
return tour_pages;
if (!record) return null;
return record.get({ plain: true });
}
const output = tour_pages.get({plain: true});
output.page_elements_page = await tour_pages.getPage_elements_page({
transaction
});
output.page_links_from_page = await tour_pages.getPage_links_from_page({
transaction
});
output.page_links_to_page = await tour_pages.getPage_links_to_page({
transaction
});
output.project = await tour_pages.getProject({
transaction
});
return output;
}
static async findAll(
filter,
options
) {
static async findAll(filter = {}, options = {}) {
filter = filter || {};
const limit = filter.limit || 0;
let offset = 0;
const currentPage = +filter.page || 0;
const offset = currentPage * limit;
let where = {};
const currentPage = +filter.page;
offset = currentPage * limit;
let include = [
{
model: db.projects,
as: 'project',
where: filter.project ? {
[Op.or]: [
{ id: { [Op.in]: filter.project.split('|').map(term => Utils.uuid(term)) } },
@ -392,194 +130,56 @@ module.exports = class Tour_pagesDBApi {
},
]
} : {},
},
];
include[0] = applyRuntimeProjectFilter(include[0], options);
if (filter) {
if (filter.id) {
where = {
...where,
['id']: Utils.uuid(filter.id),
};
where.id = Utils.uuid(filter.id);
}
if (filter.source_key) {
where = {
...where,
[Op.and]: Utils.ilike(
'tour_pages',
'source_key',
filter.source_key,
),
};
for (const field of this.SEARCHABLE_FIELDS) {
if (filter[field]) {
where[Op.and] = Utils.ilike(this.TABLE_NAME, field, filter[field]);
}
}
if (filter.name) {
where = {
...where,
[Op.and]: Utils.ilike(
'tour_pages',
'name',
filter.name,
),
};
}
if (filter.slug) {
where = {
...where,
[Op.and]: Utils.ilike(
'tour_pages',
'slug',
filter.slug,
),
};
}
if (filter.background_image_url) {
where = {
...where,
[Op.and]: Utils.ilike(
'tour_pages',
'background_image_url',
filter.background_image_url,
),
};
}
if (filter.background_video_url) {
where = {
...where,
[Op.and]: Utils.ilike(
'tour_pages',
'background_video_url',
filter.background_video_url,
),
};
}
if (filter.background_audio_url) {
where = {
...where,
[Op.and]: Utils.ilike(
'tour_pages',
'background_audio_url',
filter.background_audio_url,
),
};
}
if (filter.ui_schema_json) {
where = {
...where,
[Op.and]: Utils.ilike(
'tour_pages',
'ui_schema_json',
filter.ui_schema_json,
),
};
}
if (filter.sort_orderRange) {
const [start, end] = filter.sort_orderRange;
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 = {
...where,
sort_order: {
...where.sort_order,
[Op.gte]: start,
},
};
where[field] = { ...where[field], [Op.gte]: start };
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
sort_order: {
...where.sort_order,
[Op.lte]: 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 = {
...where,
active: filter.active === true || filter.active === 'true'
};
where.active = filter.active === true || filter.active === 'true';
}
if (filter.environment) {
where = {
...where,
environment: filter.environment,
};
}
if (filter.background_loop) {
where = {
...where,
background_loop: filter.background_loop,
};
}
if (filter.requires_auth) {
where = {
...where,
requires_auth: filter.requires_auth,
};
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.gte]: start,
},
};
where.createdAt = { ...where.createdAt, [Op.gte]: start };
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.lte]: end,
},
};
}
where.createdAt = { ...where.createdAt, [Op.lte]: end };
}
}
where = applyRuntimeEnvironment(where, options);
const queryOptions = {
where,
include,
@ -587,59 +187,25 @@ module.exports = class Tour_pagesDBApi {
order: filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log
transaction: options.transaction,
};
if (!options?.countOnly) {
if (!options.countOnly) {
queryOptions.limit = limit ? Number(limit) : undefined;
queryOptions.offset = offset ? Number(offset) : undefined;
}
try {
const { rows, count } = await db.tour_pages.findAndCountAll(queryOptions);
const { rows, count } = await this.MODEL.findAndCountAll(queryOptions);
return {
rows: options?.countOnly ? [] : rows,
count: count
rows: options.countOnly ? [] : rows,
count,
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
static async findAllAutocomplete(query, limit, offset, ) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
Utils.ilike(
'tour_pages',
'name',
query,
),
],
};
}
const records = await db.tour_pages.findAll({
attributes: [ 'id', 'name' ],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
orderBy: [['name', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.name,
}));
}
};
module.exports = Tour_pagesDBApi;

View File

@ -1,4 +1,4 @@
const GenericDBApi = require('./base.api');
const db = require('../models');
const Utils = require('../utils');
const {
@ -6,331 +6,91 @@ const {
applyRuntimeProjectFilter,
} = require('./runtime-context');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class TransitionsDBApi {
class TransitionsDBApi extends GenericDBApi {
static get MODEL() {
return db.transitions;
}
static get TABLE_NAME() {
return 'transitions';
}
static get SEARCHABLE_FIELDS() {
return ['source_key', 'name', 'slug', 'video_url', 'audio_url'];
}
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
static get RANGE_FIELDS() {
return ['duration_sec'];
}
const transitions = await db.transitions.create(
{
static get ENUM_FIELDS() {
return ['environment', 'supports_reverse'];
}
static get CSV_FIELDS() {
return ['id', 'source_key', 'name', 'slug', 'video_url', 'audio_url', 'duration_sec', 'createdAt'];
}
static get AUTOCOMPLETE_FIELD() {
return 'name';
}
static get ASSOCIATIONS() {
return [
{ field: 'project', setter: 'setProject', isArray: false },
];
}
static getFieldMapping(data) {
return {
id: data.id || undefined,
environment: data.environment
||
null
,
source_key: data.source_key
||
null
,
name: data.name
||
null
,
slug: data.slug
||
null
,
video_url: data.video_url
||
null
,
audio_url: data.audio_url
||
null
,
supports_reverse: data.supports_reverse
||
false
,
duration_sec: data.duration_sec
||
null
,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
await transitions.setProject( data.project || null, {
transaction,
});
return transitions;
environment: data.environment || null,
source_key: data.source_key || null,
name: data.name || null,
slug: data.slug || null,
video_url: data.video_url || null,
audio_url: data.audio_url || null,
supports_reverse: data.supports_reverse || false,
duration_sec: data.duration_sec || null,
};
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
// Prepare data - wrapping individual data transformations in a map() method
const transitionsData = data.map((item, index) => ({
id: item.id || undefined,
environment: item.environment
||
null
,
source_key: item.source_key
||
null
,
name: item.name
||
null
,
slug: item.slug
||
null
,
video_url: item.video_url
||
null
,
audio_url: item.audio_url
||
null
,
supports_reverse: item.supports_reverse
||
false
,
duration_sec: item.duration_sec
||
null
,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
// Bulk create items
const transitions = await db.transitions.bulkCreate(transitionsData, { transaction });
// For each item created, replace relation files
return transitions;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const transitions = await db.transitions.findByPk(id, {transaction});
const updatePayload = {};
if (data.environment !== undefined) updatePayload.environment = data.environment;
if (data.source_key !== undefined) updatePayload.source_key = data.source_key;
if (data.name !== undefined) updatePayload.name = data.name;
if (data.slug !== undefined) updatePayload.slug = data.slug;
if (data.video_url !== undefined) updatePayload.video_url = data.video_url;
if (data.audio_url !== undefined) updatePayload.audio_url = data.audio_url;
if (data.supports_reverse !== undefined) updatePayload.supports_reverse = data.supports_reverse;
if (data.duration_sec !== undefined) updatePayload.duration_sec = data.duration_sec;
updatePayload.updatedById = currentUser.id;
await transitions.update(updatePayload, {transaction});
if (data.project !== undefined) {
await transitions.setProject(
data.project,
{ transaction }
);
}
return transitions;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const transitions = await db.transitions.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (transaction) => {
for (const record of transitions) {
await record.update(
{deletedBy: currentUser.id},
{transaction}
);
}
for (const record of transitions) {
await record.destroy({transaction});
}
});
return transitions;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const transitions = await db.transitions.findByPk(id, options);
await transitions.update({
deletedBy: currentUser.id
}, {
transaction,
});
await transitions.destroy({
transaction
});
return transitions;
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
static async findBy(where, options = {}) {
const transaction = options.transaction;
const queryWhere = applyRuntimeEnvironment({ ...where }, options);
const projectInclude = applyRuntimeProjectFilter(
{
model: db.projects,
as: 'project',
},
options,
);
const transitions = await db.transitions.findOne(
{ where: queryWhere, include: [projectInclude], transaction },
);
if (!transitions) {
return transitions;
}
const output = transitions.get({plain: true});
output.page_links_transition = await transitions.getPage_links_transition({
transaction
});
output.project = await transitions.getProject({
transaction
});
return output;
}
static async findAll(
filter,
{ model: db.projects, as: 'project' },
options
) {
);
const record = await this.MODEL.findOne({
where: queryWhere,
transaction,
include: [
projectInclude,
{ association: 'page_links_transition' },
],
});
if (!record) return null;
return record.get({ plain: true });
}
static async findAll(filter = {}, options = {}) {
filter = filter || {};
const limit = filter.limit || 0;
let offset = 0;
const currentPage = +filter.page || 0;
const offset = currentPage * limit;
let where = {};
const currentPage = +filter.page;
offset = currentPage * limit;
let include = [
{
model: db.projects,
as: 'project',
where: filter.project ? {
[Op.or]: [
{ id: { [Op.in]: filter.project.split('|').map(term => Utils.uuid(term)) } },
@ -341,165 +101,56 @@ module.exports = class TransitionsDBApi {
},
]
} : {},
},
];
include[0] = applyRuntimeProjectFilter(include[0], options);
if (filter) {
if (filter.id) {
where = {
...where,
['id']: Utils.uuid(filter.id),
};
where.id = Utils.uuid(filter.id);
}
if (filter.source_key) {
where = {
...where,
[Op.and]: Utils.ilike(
'transitions',
'source_key',
filter.source_key,
),
};
for (const field of this.SEARCHABLE_FIELDS) {
if (filter[field]) {
where[Op.and] = Utils.ilike(this.TABLE_NAME, field, filter[field]);
}
}
if (filter.name) {
where = {
...where,
[Op.and]: Utils.ilike(
'transitions',
'name',
filter.name,
),
};
}
if (filter.slug) {
where = {
...where,
[Op.and]: Utils.ilike(
'transitions',
'slug',
filter.slug,
),
};
}
if (filter.video_url) {
where = {
...where,
[Op.and]: Utils.ilike(
'transitions',
'video_url',
filter.video_url,
),
};
}
if (filter.audio_url) {
where = {
...where,
[Op.and]: Utils.ilike(
'transitions',
'audio_url',
filter.audio_url,
),
};
}
if (filter.duration_secRange) {
const [start, end] = filter.duration_secRange;
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 = {
...where,
duration_sec: {
...where.duration_sec,
[Op.gte]: start,
},
};
where[field] = { ...where[field], [Op.gte]: start };
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
duration_sec: {
...where.duration_sec,
[Op.lte]: 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 = {
...where,
active: filter.active === true || filter.active === 'true'
};
where.active = filter.active === true || filter.active === 'true';
}
if (filter.environment) {
where = {
...where,
environment: filter.environment,
};
}
if (filter.supports_reverse) {
where = {
...where,
supports_reverse: filter.supports_reverse,
};
}
if (filter.createdAtRange) {
const [start, end] = filter.createdAtRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.gte]: start,
},
};
where.createdAt = { ...where.createdAt, [Op.gte]: start };
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
['createdAt']: {
...where.createdAt,
[Op.lte]: end,
},
};
}
where.createdAt = { ...where.createdAt, [Op.lte]: end };
}
}
where = applyRuntimeEnvironment(where, options);
const queryOptions = {
where,
include,
@ -507,59 +158,25 @@ module.exports = class TransitionsDBApi {
order: filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log
transaction: options.transaction,
};
if (!options?.countOnly) {
if (!options.countOnly) {
queryOptions.limit = limit ? Number(limit) : undefined;
queryOptions.offset = offset ? Number(offset) : undefined;
}
try {
const { rows, count } = await db.transitions.findAndCountAll(queryOptions);
const { rows, count } = await this.MODEL.findAndCountAll(queryOptions);
return {
rows: options?.countOnly ? [] : rows,
count: count
rows: options.countOnly ? [] : rows,
count,
};
} catch (error) {
console.error('Error executing query:', error);
throw error;
}
}
static async findAllAutocomplete(query, limit, offset, ) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
Utils.ilike(
'transitions',
'name',
query,
),
],
};
}
const records = await db.transitions.findAll({
attributes: [ 'id', 'name' ],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
orderBy: [['name', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.name,
}));
}
};
module.exports = TransitionsDBApi;

View File

@ -1,233 +0,0 @@
const db = require('../models');
const Utils = require('../utils');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class Ui_elementsDBApi {
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const ui_elements = await db.ui_elements.create(
{
id: data.id || undefined,
element_type: data.element_type ?? null,
name: data.name ?? null,
settings_json: data.settings_json ?? null,
sort_order: data.sort_order ?? 0,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
return ui_elements;
}
static async bulkImport(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const uiElementsData = data.map((item, index) => ({
id: item.id || undefined,
element_type: item.element_type ?? null,
name: item.name ?? null,
settings_json: item.settings_json ?? null,
sort_order: item.sort_order ?? 0,
importHash: item.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
createdAt: new Date(Date.now() + index * 1000),
}));
const ui_elements = await db.ui_elements.bulkCreate(uiElementsData, { transaction });
return ui_elements;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const ui_elements = await db.ui_elements.findByPk(id, { transaction });
const updatePayload = {};
if (data.element_type !== undefined) updatePayload.element_type = data.element_type;
if (data.name !== undefined) updatePayload.name = data.name;
if (data.settings_json !== undefined) updatePayload.settings_json = data.settings_json;
if (data.sort_order !== undefined) updatePayload.sort_order = data.sort_order;
updatePayload.updatedById = currentUser.id;
await ui_elements.update(updatePayload, { transaction });
return ui_elements;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const ui_elements = await db.ui_elements.findAll({
where: {
id: {
[Op.in]: ids,
},
},
transaction,
});
await db.sequelize.transaction(async (innerTransaction) => {
for (const record of ui_elements) {
await record.update({ deletedBy: currentUser.id }, { transaction: innerTransaction });
}
for (const record of ui_elements) {
await record.destroy({ transaction: innerTransaction });
}
});
return ui_elements;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const ui_elements = await db.ui_elements.findByPk(id, options);
await ui_elements.update(
{
deletedBy: currentUser.id,
},
{
transaction,
},
);
await ui_elements.destroy({
transaction,
});
return ui_elements;
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
const ui_elements = await db.ui_elements.findOne({ where, transaction });
if (!ui_elements) {
return ui_elements;
}
return ui_elements.get({ plain: true });
}
static async findAll(filter, options) {
filter = filter || {};
const limit = Number(filter.limit) || 0;
const currentPage = Number(filter.page) || 0;
const offset = limit ? currentPage * limit : undefined;
let where = {};
if (filter.id) {
where = {
...where,
id: Utils.uuid(filter.id),
};
}
if (filter.name) {
where = {
...where,
[Op.and]: Utils.ilike('ui_elements', 'name', filter.name),
};
}
if (filter.element_type) {
where = {
...where,
element_type: filter.element_type,
};
}
if (filter.sort_orderRange) {
const [start, end] = filter.sort_orderRange;
if (start !== undefined && start !== null && start !== '') {
where = {
...where,
sort_order: {
...where.sort_order,
[Op.gte]: start,
},
};
}
if (end !== undefined && end !== null && end !== '') {
where = {
...where,
sort_order: {
...where.sort_order,
[Op.lte]: end,
},
};
}
}
let { orderBy = null } = options || {};
if (!orderBy) {
const sort = filter.sort || 'desc';
const field = filter.field || 'createdAt';
orderBy = [[field, sort]];
}
const { rows, count } = await db.ui_elements.findAndCountAll({
where,
limit: limit || undefined,
offset,
order: orderBy,
});
return {
rows,
count,
};
}
static async findAllAutocomplete(query, limit) {
let where = {};
if (query) {
where = {
[Op.or]: [
{
id: {
[Op.eq]: Utils.uuid(query),
},
},
{
name: {
[Op.iLike]: `%${query}%`,
},
},
],
};
}
const records = await db.ui_elements.findAll({
attributes: ['id', 'name'],
where,
limit: Number(limit) || undefined,
order: [['name', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.name,
}));
}
};

View File

@ -391,6 +391,18 @@ module.exports = class UsersDBApi {
const users = await db.users.findOne({
where,
transaction,
include: [
{ association: 'project_memberships_user' },
{ association: 'presigned_url_requests_user' },
{ association: 'publish_events_user' },
{ association: 'access_logs_user' },
{ association: 'avatar' },
{
association: 'app_role',
include: [{ association: 'permissions' }],
},
{ association: 'custom_permissions' },
],
});
if (!users) {
@ -399,62 +411,11 @@ module.exports = class UsersDBApi {
const output = users.get({plain: true});
output.project_memberships_user = await users.getProject_memberships_user({
transaction
});
output.presigned_url_requests_user = await users.getPresigned_url_requests_user({
transaction
});
output.publish_events_user = await users.getPublish_events_user({
transaction
});
output.access_logs_user = await users.getAccess_logs_user({
transaction
});
output.avatar = await users.getAvatar({
transaction
});
output.app_role = await users.getApp_role({
transaction
});
// Map nested permissions from app_role for backward compatibility
if (output.app_role) {
output.app_role_permissions = await output.app_role.getPermissions({
transaction,
});
output.app_role_permissions = output.app_role.permissions || [];
}
output.custom_permissions = await users.getCustom_permissions({
transaction
});
return output;
}
@ -744,8 +705,7 @@ module.exports = class UsersDBApi {
order: filter.field && filter.sort
? [[filter.field, filter.sort]]
: [['createdAt', 'desc']],
transaction: options?.transaction,
logging: console.log
transaction: options?.transaction
};
if (!options?.countOnly) {
@ -921,7 +881,9 @@ module.exports = class UsersDBApi {
const token = crypto
.randomBytes(20)
.toString('hex');
const tokenExpiresAt = Date.now() + 360000;
// Token expires in 24 hours (was 6 minutes - too short for email verification flows)
const TOKEN_EXPIRY_MS = 24 * 60 * 60 * 1000; // 24 hours
const tokenExpiresAt = Date.now() + TOKEN_EXPIRY_MS;
if(users){
await users.update(

View File

@ -8,7 +8,7 @@ module.exports = {
database: process.env.DB_NAME,
host: process.env.DB_HOST,
port: process.env.DB_PORT,
logging: console.log,
logging: false,
seederStorage: 'sequelize',
},
development: {

File diff suppressed because it is too large Load Diff

View File

@ -1,124 +0,0 @@
module.exports = {
async up(queryInterface, Sequelize) {
const transaction = await queryInterface.sequelize.transaction();
try {
const rows = await queryInterface.sequelize.query(
"SELECT to_regclass('public.files') AS regclass_name;",
{
transaction,
type: Sequelize.QueryTypes.SELECT,
},
);
const tableName = rows[0].regclass_name;
if (tableName) {
await transaction.commit();
return;
}
await queryInterface.createTable(
'files',
{
id: {
type: Sequelize.DataTypes.UUID,
defaultValue: Sequelize.DataTypes.UUIDV4,
primaryKey: true,
},
belongsTo: {
type: Sequelize.DataTypes.STRING(255),
allowNull: true,
},
belongsToId: {
type: Sequelize.DataTypes.UUID,
allowNull: true,
},
belongsToColumn: {
type: Sequelize.DataTypes.STRING(255),
allowNull: true,
},
name: {
type: Sequelize.DataTypes.STRING(2083),
allowNull: false,
},
sizeInBytes: {
type: Sequelize.DataTypes.INTEGER,
allowNull: true,
},
privateUrl: {
type: Sequelize.DataTypes.STRING(2083),
allowNull: true,
},
publicUrl: {
type: Sequelize.DataTypes.STRING(2083),
allowNull: false,
},
createdAt: {
type: Sequelize.DataTypes.DATE,
allowNull: false,
},
updatedAt: {
type: Sequelize.DataTypes.DATE,
allowNull: false,
},
deletedAt: {
type: Sequelize.DataTypes.DATE,
allowNull: true,
},
createdById: {
type: Sequelize.DataTypes.UUID,
allowNull: true,
references: {
key: 'id',
model: 'users',
},
onDelete: 'SET NULL',
onUpdate: 'CASCADE',
},
updatedById: {
type: Sequelize.DataTypes.UUID,
allowNull: true,
references: {
key: 'id',
model: 'users',
},
onDelete: 'SET NULL',
onUpdate: 'CASCADE',
},
},
{ transaction },
);
await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
}
},
async down(queryInterface, Sequelize) {
const transaction = await queryInterface.sequelize.transaction();
try {
const rows = await queryInterface.sequelize.query(
"SELECT to_regclass('public.files') AS regclass_name;",
{
transaction,
type: Sequelize.QueryTypes.SELECT,
},
);
const tableName = rows[0].regclass_name;
if (!tableName) {
await transaction.commit();
return;
}
await queryInterface.dropTable('files', { transaction });
await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
}
},
};

View File

@ -1,95 +0,0 @@
module.exports = {
async up(queryInterface, Sequelize) {
const transaction = await queryInterface.sequelize.transaction();
try {
const rows = await queryInterface.sequelize.query(
"SELECT to_regclass('public.\"usersCustom_permissionsPermissions\"') AS regclass_name;",
{
transaction,
type: Sequelize.QueryTypes.SELECT,
},
);
const tableName = rows[0].regclass_name;
if (tableName) {
await transaction.commit();
return;
}
await queryInterface.createTable(
'usersCustom_permissionsPermissions',
{
createdAt: {
type: Sequelize.DataTypes.DATE,
allowNull: false,
},
updatedAt: {
type: Sequelize.DataTypes.DATE,
allowNull: false,
},
users_custom_permissionsId: {
type: Sequelize.DataTypes.UUID,
allowNull: false,
primaryKey: true,
references: {
model: 'users',
key: 'id',
},
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
},
permissionId: {
type: Sequelize.DataTypes.UUID,
allowNull: false,
primaryKey: true,
references: {
model: 'permissions',
key: 'id',
},
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
},
},
{ transaction },
);
await queryInterface.addIndex(
'usersCustom_permissionsPermissions',
['permissionId'],
{ transaction },
);
await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
}
},
async down(queryInterface, Sequelize) {
const transaction = await queryInterface.sequelize.transaction();
try {
const rows = await queryInterface.sequelize.query(
"SELECT to_regclass('public.\"usersCustom_permissionsPermissions\"') AS regclass_name;",
{
transaction,
type: Sequelize.QueryTypes.SELECT,
},
);
const tableName = rows[0].regclass_name;
if (!tableName) {
await transaction.commit();
return;
}
await queryInterface.dropTable('usersCustom_permissionsPermissions', { transaction });
await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
}
},
};

View File

@ -1,123 +0,0 @@
module.exports = {
async up(queryInterface, Sequelize) {
const transaction = await queryInterface.sequelize.transaction();
try {
const tableRows = await queryInterface.sequelize.query(
"SELECT to_regclass('public.page_elements') AS regclass_name;",
{
transaction,
type: Sequelize.QueryTypes.SELECT,
},
);
if (!tableRows[0]?.regclass_name) {
await transaction.commit();
return;
}
const nullableRows = await queryInterface.sequelize.query(
`SELECT is_nullable
FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'page_elements'
AND column_name = 'pageId';`,
{
transaction,
type: Sequelize.QueryTypes.SELECT,
},
);
if (!nullableRows.length || nullableRows[0].is_nullable === 'YES') {
await transaction.commit();
return;
}
await queryInterface.changeColumn(
'page_elements',
'pageId',
{
type: Sequelize.DataTypes.UUID,
allowNull: true,
references: {
model: 'tour_pages',
key: 'id',
},
},
{ transaction },
);
await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
}
},
async down(queryInterface, Sequelize) {
const transaction = await queryInterface.sequelize.transaction();
try {
const tableRows = await queryInterface.sequelize.query(
"SELECT to_regclass('public.page_elements') AS regclass_name;",
{
transaction,
type: Sequelize.QueryTypes.SELECT,
},
);
if (!tableRows[0]?.regclass_name) {
await transaction.commit();
return;
}
const nullableRows = await queryInterface.sequelize.query(
`SELECT is_nullable
FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'page_elements'
AND column_name = 'pageId';`,
{
transaction,
type: Sequelize.QueryTypes.SELECT,
},
);
if (!nullableRows.length || nullableRows[0].is_nullable === 'NO') {
await transaction.commit();
return;
}
const nullCountRows = await queryInterface.sequelize.query(
'SELECT COUNT(*)::int AS count FROM "page_elements" WHERE "pageId" IS NULL;',
{
transaction,
type: Sequelize.QueryTypes.SELECT,
},
);
if (Number(nullCountRows[0]?.count || 0) > 0) {
throw new Error('Cannot make page_elements.pageId NOT NULL because NULL values exist.');
}
await queryInterface.changeColumn(
'page_elements',
'pageId',
{
type: Sequelize.DataTypes.UUID,
allowNull: false,
references: {
model: 'tour_pages',
key: 'id',
},
},
{ transaction },
);
await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
}
},
};

View File

@ -1,105 +0,0 @@
module.exports = {
async up(queryInterface, Sequelize) {
const transaction = await queryInterface.sequelize.transaction();
try {
const tableRows = await queryInterface.sequelize.query(
"SELECT to_regclass('public.page_elements') AS regclass_name;",
{
transaction,
type: Sequelize.QueryTypes.SELECT,
},
);
if (!tableRows[0]?.regclass_name) {
await transaction.commit();
return;
}
const nullableRows = await queryInterface.sequelize.query(
`SELECT is_nullable
FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'page_elements'
AND column_name = 'pageId';`,
{
transaction,
type: Sequelize.QueryTypes.SELECT,
},
);
if (!nullableRows.length || nullableRows[0].is_nullable === 'YES') {
await transaction.commit();
return;
}
await queryInterface.sequelize.query(
'ALTER TABLE "page_elements" ALTER COLUMN "pageId" DROP NOT NULL;',
{ transaction },
);
await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
}
},
async down(queryInterface, Sequelize) {
const transaction = await queryInterface.sequelize.transaction();
try {
const tableRows = await queryInterface.sequelize.query(
"SELECT to_regclass('public.page_elements') AS regclass_name;",
{
transaction,
type: Sequelize.QueryTypes.SELECT,
},
);
if (!tableRows[0]?.regclass_name) {
await transaction.commit();
return;
}
const nullableRows = await queryInterface.sequelize.query(
`SELECT is_nullable
FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'page_elements'
AND column_name = 'pageId';`,
{
transaction,
type: Sequelize.QueryTypes.SELECT,
},
);
if (!nullableRows.length || nullableRows[0].is_nullable === 'NO') {
await transaction.commit();
return;
}
const nullCountRows = await queryInterface.sequelize.query(
'SELECT COUNT(*)::int AS count FROM "page_elements" WHERE "pageId" IS NULL;',
{
transaction,
type: Sequelize.QueryTypes.SELECT,
},
);
if (Number(nullCountRows[0]?.count || 0) > 0) {
throw new Error('Cannot make page_elements.pageId NOT NULL because NULL values exist.');
}
await queryInterface.sequelize.query(
'ALTER TABLE "page_elements" ALTER COLUMN "pageId" SET NOT NULL;',
{ transaction },
);
await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
}
},
};

View File

@ -1,108 +0,0 @@
module.exports = {
async up(queryInterface, Sequelize) {
const transaction = await queryInterface.sequelize.transaction();
try {
const tableRows = await queryInterface.sequelize.query(
"SELECT to_regclass('public.ui_elements') AS regclass_name;",
{
transaction,
type: Sequelize.QueryTypes.SELECT,
},
);
if (tableRows[0]?.regclass_name) {
await transaction.commit();
return;
}
await queryInterface.createTable(
'ui_elements',
{
id: {
type: Sequelize.DataTypes.UUID,
defaultValue: Sequelize.DataTypes.UUIDV4,
primaryKey: true,
},
element_type: {
type: Sequelize.DataTypes.TEXT,
allowNull: false,
},
name: {
type: Sequelize.DataTypes.TEXT,
allowNull: true,
},
settings_json: {
type: Sequelize.DataTypes.TEXT,
allowNull: true,
},
sort_order: {
type: Sequelize.DataTypes.INTEGER,
allowNull: false,
defaultValue: 0,
},
createdById: {
type: Sequelize.DataTypes.UUID,
allowNull: true,
references: {
model: 'users',
key: 'id',
},
},
updatedById: {
type: Sequelize.DataTypes.UUID,
allowNull: true,
references: {
model: 'users',
key: 'id',
},
},
createdAt: { type: Sequelize.DataTypes.DATE },
updatedAt: { type: Sequelize.DataTypes.DATE },
deletedAt: { type: Sequelize.DataTypes.DATE },
importHash: {
type: Sequelize.DataTypes.STRING(255),
allowNull: true,
unique: true,
},
},
{ transaction },
);
await queryInterface.addIndex('ui_elements', ['element_type'], { transaction });
await queryInterface.addIndex('ui_elements', ['sort_order'], { transaction });
await queryInterface.addIndex('ui_elements', ['deletedAt'], { transaction });
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
},
async down(queryInterface, Sequelize) {
const transaction = await queryInterface.sequelize.transaction();
try {
const tableRows = await queryInterface.sequelize.query(
"SELECT to_regclass('public.ui_elements') AS regclass_name;",
{
transaction,
type: Sequelize.QueryTypes.SELECT,
},
);
if (!tableRows[0]?.regclass_name) {
await transaction.commit();
return;
}
await queryInterface.dropTable('ui_elements', { transaction });
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
},
};

View File

@ -1,85 +0,0 @@
module.exports = {
async up(queryInterface, Sequelize) {
const transaction = await queryInterface.sequelize.transaction();
try {
const tableRows = await queryInterface.sequelize.query(
"SELECT to_regclass('public.publish_events') AS regclass_name;",
{
transaction,
type: Sequelize.QueryTypes.SELECT,
},
);
if (!tableRows[0]?.regclass_name) {
await transaction.commit();
return;
}
const tableDefinition = await queryInterface.describeTable('publish_events', { transaction });
if (!tableDefinition.title) {
await queryInterface.addColumn(
'publish_events',
'title',
{
type: Sequelize.DataTypes.STRING,
allowNull: true,
},
{ transaction },
);
}
if (!tableDefinition.description) {
await queryInterface.addColumn(
'publish_events',
'description',
{
type: Sequelize.DataTypes.TEXT,
allowNull: true,
},
{ transaction },
);
}
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
},
async down(queryInterface, Sequelize) {
const transaction = await queryInterface.sequelize.transaction();
try {
const tableRows = await queryInterface.sequelize.query(
"SELECT to_regclass('public.publish_events') AS regclass_name;",
{
transaction,
type: Sequelize.QueryTypes.SELECT,
},
);
if (!tableRows[0]?.regclass_name) {
await transaction.commit();
return;
}
const tableDefinition = await queryInterface.describeTable('publish_events', { transaction });
if (tableDefinition.description) {
await queryInterface.removeColumn('publish_events', 'description', { transaction });
}
if (tableDefinition.title) {
await queryInterface.removeColumn('publish_events', 'title', { transaction });
}
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
},
};

View File

@ -28,23 +28,23 @@ environment: {
path: {
type: DataTypes.TEXT,
validate: {
len: { args: [0, 2048], msg: 'Path must be at most 2048 characters' },
},
},
ip_address: {
type: DataTypes.TEXT,
validate: {
len: { args: [0, 45], msg: 'IP address must be at most 45 characters' },
},
},
user_agent: {
type: DataTypes.TEXT,
validate: {
len: { args: [0, 1024], msg: 'User agent must be at most 1024 characters' },
},
},
accessed_at: {

View File

@ -38,30 +38,35 @@ variant_type: {
cdn_url: {
type: DataTypes.TEXT,
validate: {
len: { args: [0, 2048], msg: 'CDN URL must be at most 2048 characters' },
isUrlOrEmpty(value) {
if (value && value.length > 0 && !/^https?:\/\/.+/.test(value)) {
throw new Error('CDN URL must be a valid URL');
}
},
},
},
width_px: {
type: DataTypes.INTEGER,
validate: {
min: { args: [0], msg: 'Width must be a non-negative integer' },
},
},
height_px: {
type: DataTypes.INTEGER,
validate: {
min: { args: [0], msg: 'Height must be a non-negative integer' },
},
},
size_mb: {
type: DataTypes.DECIMAL,
validate: {
min: { args: [0], msg: 'Size must be a non-negative number' },
},
},
importHash: {

View File

@ -10,9 +10,9 @@ module.exports = function(sequelize, DataTypes) {
name: {
type: DataTypes.TEXT,
validate: {
len: { args: [0, 255], msg: 'Asset name must be at most 255 characters' },
},
},
asset_type: {
@ -36,6 +36,43 @@ asset_type: {
},
type: {
type: DataTypes.ENUM,
allowNull: false,
defaultValue: "general",
values: [
"icon",
"background_image",
"audio",
"video",
"transition",
"logo",
"favicon",
"document",
"general"
],
},
cdn_url: {
type: DataTypes.TEXT,
@ -52,9 +89,9 @@ storage_key: {
mime_type: {
type: DataTypes.TEXT,
validate: {
is: { args: /^[a-z0-9]+\/[a-z0-9.+-]+$/i, msg: 'Invalid MIME type format' },
},
},
size_mb: {
@ -132,6 +169,7 @@ deleted_at_time: {
indexes: [
{ fields: ['projectId'] },
{ fields: ['asset_type'] },
{ fields: ['type'] },
{ fields: ['is_public'] },
{ fields: ['is_deleted'] },
{ fields: ['deletedAt'] },
@ -198,4 +236,3 @@ deleted_at_time: {
return assets;
};

View File

@ -46,9 +46,9 @@ element_type: {
name: {
type: DataTypes.TEXT,
validate: {
len: { args: [0, 255], msg: 'Element name must be at most 255 characters' },
},
},
sort_order: {
@ -104,17 +104,11 @@ rotation_deg: {
},
style_json: {
type: DataTypes.TEXT,
type: DataTypes.JSON,
},
content_json: {
type: DataTypes.TEXT,
type: DataTypes.JSON,
},
importHash: {
@ -167,6 +161,7 @@ content_json: {
as: 'page',
foreignKey: {
name: 'pageId',
allowNull: false,
},
constraints: false,
});

View File

@ -29,26 +29,27 @@ direction: {
external_url: {
type: DataTypes.TEXT,
validate: {
len: { args: [0, 2048], msg: 'External URL must be at most 2048 characters' },
isUrlOrEmpty(value) {
if (value && value.length > 0 && !/^https?:\/\/.+/.test(value)) {
throw new Error('External URL must be a valid URL');
}
},
},
},
is_active: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false,
},
trigger_selector: {
type: DataTypes.TEXT,
validate: {
len: { args: [0, 1024], msg: 'Trigger selector must be at most 1024 characters' },
},
},
importHash: {

View File

@ -10,9 +10,12 @@ module.exports = function(sequelize, DataTypes) {
name: {
type: DataTypes.TEXT,
allowNull: false,
unique: true,
validate: {
notEmpty: { msg: 'Permission name is required' },
len: { args: [1, 100], msg: 'Permission name must be between 1 and 100 characters' },
},
},
importHash: {

View File

@ -48,23 +48,28 @@ asset_type: {
requested_key: {
type: DataTypes.TEXT,
validate: {
len: { args: [0, 1024], msg: 'Requested key must be at most 1024 characters' },
},
},
mime_type: {
type: DataTypes.TEXT,
validate: {
len: { args: [0, 255], msg: 'MIME type must be at most 255 characters' },
isMimeTypeOrEmpty(value) {
if (value && value.length > 0 && !/^[\w.-]+\/[\w.+-]+$/.test(value)) {
throw new Error('MIME type must be in format type/subtype');
}
},
},
},
requested_size_mb: {
type: DataTypes.DECIMAL,
validate: {
min: { args: [0], msg: 'Requested size must be a non-negative number' },
},
},
expires_at: {

View File

@ -36,9 +36,9 @@ source_key: {
name: {
type: DataTypes.TEXT,
validate: {
len: { args: [0, 255], msg: 'Audio track name must be at most 255 characters' },
},
},
slug: {
@ -67,9 +67,10 @@ loop: {
volume: {
type: DataTypes.DECIMAL,
validate: {
min: { args: [0], msg: 'Volume must be at least 0' },
max: { args: [1], msg: 'Volume must be at most 1' },
},
},
sort_order: {

View File

@ -11,14 +11,21 @@ module.exports = function(sequelize, DataTypes) {
name: {
type: DataTypes.TEXT,
allowNull: false,
validate: {
notEmpty: { msg: 'Project name is required' },
len: { args: [1, 255], msg: 'Project name must be between 1 and 255 characters' },
},
},
slug: {
type: DataTypes.TEXT,
allowNull: false,
unique: true,
validate: {
notEmpty: { msg: 'Slug is required' },
is: { args: /^[a-z0-9_-]+$/i, msg: 'Slug can only contain letters, numbers, dashes, and underscores' },
len: { args: [1, 255], msg: 'Slug must be between 1 and 255 characters' },
},
},
description: {
@ -69,17 +76,11 @@ og_image_url: {
},
theme_config_json: {
type: DataTypes.TEXT,
type: DataTypes.JSON,
},
custom_css_json: {
type: DataTypes.TEXT,
type: DataTypes.JSON,
},
cdn_base_url: {

View File

@ -11,13 +11,17 @@ module.exports = function(sequelize, DataTypes) {
title: {
type: DataTypes.STRING,
allowNull: true,
validate: {
len: { args: [0, 255], msg: 'Title must be at most 255 characters' },
},
},
description: {
type: DataTypes.TEXT,
allowNull: true,
validate: {
len: { args: [0, 5000], msg: 'Description must be at most 5000 characters' },
},
},
from_environment: {
@ -101,23 +105,23 @@ error_message: {
pages_copied: {
type: DataTypes.INTEGER,
validate: {
min: { args: [0], msg: 'Pages copied must be a non-negative integer' },
},
},
transitions_copied: {
type: DataTypes.INTEGER,
validate: {
min: { args: [0], msg: 'Transitions copied must be a non-negative integer' },
},
},
audios_copied: {
type: DataTypes.INTEGER,
validate: {
min: { args: [0], msg: 'Audios copied must be a non-negative integer' },
},
},
importHash: {

View File

@ -15,6 +15,9 @@ environment: {
values: [
"dev",
"stage",
@ -26,23 +29,17 @@ environment: {
cache_version: {
type: DataTypes.TEXT,
validate: {
len: { args: [0, 255], msg: 'Cache version must be at most 255 characters' },
},
},
manifest_json: {
type: DataTypes.TEXT,
type: DataTypes.JSON,
},
asset_list_json: {
type: DataTypes.TEXT,
type: DataTypes.JSON,
},
generated_at: {

View File

@ -10,9 +10,11 @@ module.exports = function(sequelize, DataTypes) {
name: {
type: DataTypes.TEXT,
allowNull: false,
validate: {
notEmpty: { msg: 'Role name is required' },
len: { args: [1, 100], msg: 'Role name must be between 1 and 100 characters' },
},
},
role_customization: {

View File

@ -37,13 +37,20 @@ source_key: {
name: {
type: DataTypes.TEXT,
allowNull: false,
validate: {
notEmpty: { msg: 'Page name is required' },
len: { args: [1, 255], msg: 'Page name must be between 1 and 255 characters' },
},
},
slug: {
type: DataTypes.TEXT,
allowNull: false,
validate: {
notEmpty: { msg: 'Slug is required' },
is: { args: /^[a-z0-9_-]+$/i, msg: 'Slug can only contain letters, numbers, dashes, and underscores' },
len: { args: [1, 255], msg: 'Slug must be between 1 and 255 characters' },
},
},
sort_order: {
@ -95,10 +102,7 @@ requires_auth: {
},
ui_schema_json: {
type: DataTypes.TEXT,
type: DataTypes.JSON,
},
importHash: {

View File

@ -37,13 +37,20 @@ source_key: {
name: {
type: DataTypes.TEXT,
allowNull: false,
validate: {
notEmpty: { msg: 'Transition name is required' },
len: { args: [1, 255], msg: 'Transition name must be between 1 and 255 characters' },
},
},
slug: {
type: DataTypes.TEXT,
allowNull: false,
validate: {
notEmpty: { msg: 'Slug is required' },
is: { args: /^[a-z0-9_-]+$/i, msg: 'Slug can only contain letters, numbers, dashes, and underscores' },
len: { args: [1, 255], msg: 'Slug must be between 1 and 255 characters' },
},
},
video_url: {

View File

@ -1,50 +0,0 @@
module.exports = function (sequelize, DataTypes) {
const ui_elements = sequelize.define(
'ui_elements',
{
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
},
element_type: {
type: DataTypes.TEXT,
allowNull: false,
},
name: {
type: DataTypes.TEXT,
},
settings_json: {
type: DataTypes.TEXT,
},
sort_order: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0,
},
importHash: {
type: DataTypes.STRING(255),
allowNull: true,
unique: true,
},
},
{
timestamps: true,
paranoid: true,
freezeTableName: true,
indexes: [{ fields: ['element_type'] }, { fields: ['sort_order'] }, { fields: ['deletedAt'] }],
},
);
ui_elements.associate = (db) => {
db.ui_elements.belongsTo(db.users, {
as: 'createdBy',
});
db.ui_elements.belongsTo(db.users, {
as: 'updatedBy',
});
};
return ui_elements;
};

View File

@ -38,7 +38,10 @@ email: {
type: DataTypes.TEXT,
allowNull: false,
unique: true,
validate: {
isEmail: { msg: 'Must be a valid email address' },
notEmpty: { msg: 'Email is required' },
},
},
disabled: {

View File

@ -68,7 +68,7 @@ await queryInterface.bulkInsert("permissions", [{ id: getId(`READ_API_DOCS`), cr
await queryInterface.bulkInsert("permissions", [{ id: getId(`CREATE_SEARCH`), createdAt, updatedAt, name: `CREATE_SEARCH`}]);
await queryInterface.sequelize.query(`create table "rolesPermissionsPermissions"
await queryInterface.sequelize.query(`CREATE TABLE IF NOT EXISTS "rolesPermissionsPermissions"
(
"createdAt" timestamp with time zone not null,
"updatedAt" timestamp with time zone not null,
@ -84,7 +84,7 @@ constraint "rolesPermissionsPermissions_permission_fk"
);`);
await queryInterface.sequelize.query(
'create index "rolesPermissionsPermissions_permission_idx" on "rolesPermissionsPermissions" ("permissionId");',
'CREATE INDEX IF NOT EXISTS "rolesPermissionsPermissions_permission_idx" ON "rolesPermissionsPermissions" ("permissionId");',
);

15
backend/src/db/sync.js Normal file
View File

@ -0,0 +1,15 @@
const db = require('./models');
async function syncDatabase() {
try {
console.log('Syncing database...');
await db.sequelize.sync({ force: true });
console.log('Database synced successfully!');
process.exit(0);
} catch (error) {
console.error('Error syncing database:', error);
process.exit(1);
}
}
syncDatabase();

View File

@ -0,0 +1,101 @@
const express = require('express');
const { wrapAsync, commonErrorHandler } = require('../helpers');
const { checkCrudPermissions } = require('../middlewares/check-permissions');
const { parse } = require('json2csv');
const isUuidV4 = (value) =>
/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
function createEntityRouter(entityName, Service, DBApi, options = {}) {
const router = express.Router();
const permissionEntity = options.permissionEntity || entityName;
router.use(checkCrudPermissions(permissionEntity));
router.post('/', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
const payload = await Service.create(req.body.data, req.currentUser, true, link.host);
res.status(200).send(payload);
}));
router.post('/bulk-import', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Service.bulkImport(req, res, true, link.host);
res.status(200).send(true);
}));
router.put('/:id', wrapAsync(async (req, res) => {
await Service.update(req.body.data, req.body.id, req.currentUser);
res.status(200).send(true);
}));
router.delete('/:id', wrapAsync(async (req, res) => {
await Service.remove(req.params.id, req.currentUser);
res.status(200).send(true);
}));
router.post('/deleteByIds', wrapAsync(async (req, res) => {
await Service.deleteByIds(req.body.data, req.currentUser);
res.status(200).send(true);
}));
router.get('/', wrapAsync(async (req, res) => {
const filetype = req.query.filetype;
const currentUser = req.currentUser;
const runtimeContext = req.runtimeContext;
const payload = await DBApi.findAll(req.query, { currentUser, runtimeContext });
if (filetype === 'csv') {
const fields = options.csvFields || DBApi.CSV_FIELDS || ['id', 'createdAt'];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment('export.csv').send(csv);
} catch (err) {
console.error(err);
res.status(500).send('CSV export error');
}
} else {
res.status(200).send(payload);
}
}));
router.get('/count', wrapAsync(async (req, res) => {
const currentUser = req.currentUser;
const runtimeContext = req.runtimeContext;
const payload = await DBApi.findAll(req.query, { countOnly: true, currentUser, runtimeContext });
res.status(200).send(payload);
}));
router.get('/autocomplete', async (req, res) => {
const payload = await DBApi.findAllAutocomplete(
req.query.query,
req.query.limit,
req.query.offset
);
res.status(200).send(payload);
});
router.get('/:id', wrapAsync(async (req, res) => {
if (!isUuidV4(req.params.id)) {
return res.status(400).send(`Invalid ${entityName} id`);
}
const runtimeContext = req.runtimeContext;
const payload = await DBApi.findBy({ id: req.params.id }, { runtimeContext });
res.status(200).send(payload);
}));
if (options.customRoutes) {
options.customRoutes(router, Service, DBApi);
}
router.use('/', commonErrorHandler);
return router;
}
module.exports = { createEntityRouter, isUuidV4 };

View File

@ -0,0 +1,97 @@
const db = require('../db/models');
const processFile = require('../middlewares/upload');
const ValidationError = require('../services/notifications/errors/validation');
const csv = require('csv-parser');
const stream = require('stream');
function createEntityService(DBApi, options = {}) {
const entityName = options.entityName || 'Entity';
return class GenericService {
static async create(data, currentUser) {
const transaction = await db.sequelize.transaction();
try {
const record = await DBApi.create(data, { currentUser, transaction });
await transaction.commit();
return record;
} catch (error) {
await transaction.rollback();
throw error;
}
}
static async bulkImport(req, res) {
const transaction = await db.sequelize.transaction();
try {
await processFile(req, res);
const bufferStream = new stream.PassThrough();
const results = [];
await bufferStream.end(Buffer.from(req.file.buffer, 'utf-8'));
await new Promise((resolve, reject) => {
bufferStream
.pipe(csv())
.on('data', (data) => results.push(data))
.on('end', () => resolve())
.on('error', (error) => reject(error));
});
await DBApi.bulkImport(results, {
transaction,
ignoreDuplicates: true,
validate: true,
currentUser: req.currentUser,
});
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
}
static async update(data, id, currentUser) {
const transaction = await db.sequelize.transaction();
try {
const record = await DBApi.findBy({ id }, { transaction });
if (!record) {
throw new ValidationError(`${entityName}NotFound`);
}
const updated = await DBApi.update(id, data, { currentUser, transaction });
await transaction.commit();
return updated;
} catch (error) {
await transaction.rollback();
throw error;
}
}
static async deleteByIds(ids, currentUser) {
const transaction = await db.sequelize.transaction();
try {
await DBApi.deleteByIds(ids, { currentUser, transaction });
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
}
static async remove(id, currentUser) {
const transaction = await db.sequelize.transaction();
try {
await DBApi.remove(id, { currentUser, transaction });
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
}
};
}
module.exports = { createEntityService };

View File

@ -9,6 +9,7 @@ const bodyParser = require('body-parser');
const config = require('./config');
const swaggerUI = require('swagger-ui-express');
const swaggerJsDoc = require('swagger-jsdoc');
const { logger, requestLogger } = require('./utils/logger');
const authRoutes = require('./routes/auth');
const fileRoutes = require('./routes/file');
@ -39,7 +40,6 @@ const presigned_url_requestsRoutes = require('./routes/presigned_url_requests');
const tour_pagesRoutes = require('./routes/tour_pages');
const page_elementsRoutes = require('./routes/page_elements');
const ui_elementsRoutes = require('./routes/ui_elements');
const page_linksRoutes = require('./routes/page_links');
@ -120,6 +120,7 @@ require('./auth/auth');
app.use(bodyParser.json({ limit: '1mb' }));
app.use(bodyParser.urlencoded({ extended: true, limit: '1mb' }));
app.use(requestLogger);
app.use(runtimeContextMiddleware);
const jwtAuth = passport.authenticate('jwt', { session: false });
@ -137,6 +138,29 @@ const requireRuntimeReadOrAuth = (req, res, next) => {
return jwtAuth(req, res, next);
};
// Health check endpoint (no auth required)
app.get('/api/health', async (req, res) => {
const db = require('./db/models');
const health = {
status: 'ok',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
environment: process.env.NODE_ENV || 'development',
};
try {
await db.sequelize.authenticate();
health.database = 'connected';
} catch (error) {
health.status = 'degraded';
health.database = 'disconnected';
health.databaseError = error.message;
}
const statusCode = health.status === 'ok' ? 200 : 503;
res.status(statusCode).json(health);
});
app.use('/api/auth', authRoutes);
app.use('/api/file', fileRoutes);
app.use('/api/pexels', pexelsRoutes);
@ -172,7 +196,6 @@ app.use('/api/presigned_url_requests', jwtAuth, presigned_url_requestsRoutes);
mountRuntimeEntityRoute('/api/tour_pages', 'tour_pages', tour_pagesRoutes);
mountRuntimeEntityRoute('/api/page_elements', 'page_elements', page_elementsRoutes);
app.use('/api/ui-elements', jwtAuth, ui_elementsRoutes);
mountRuntimeEntityRoute('/api/page_links', 'page_links', page_linksRoutes);
@ -227,7 +250,7 @@ if (fs.existsSync(publicDir)) {
const PORT = process.env.NODE_ENV === 'dev_stage' ? 3000 : 8080;
app.listen(PORT, () => {
console.log(`Listening on port ${PORT}`);
logger.info({ port: PORT, env: process.env.NODE_ENV || 'development' }, 'Server started');
});
module.exports = app;

View File

@ -0,0 +1,103 @@
const { body, param, query, validationResult } = require('express-validator');
const handleValidationErrors = (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
error: 'Validation failed',
details: errors.array().map(err => ({
field: err.path,
message: err.msg,
value: err.value,
})),
});
}
next();
};
const validators = {
uuid: (field, location = 'param') => {
const validator = location === 'param' ? param(field) : body(field);
return validator.isUUID().withMessage(`${field} must be a valid UUID`);
},
requiredString: (field, min = 1, max = 255) =>
body(field)
.trim()
.notEmpty().withMessage(`${field} is required`)
.isLength({ min, max }).withMessage(`${field} must be ${min}-${max} characters`),
optionalString: (field, max = 255) =>
body(field)
.optional()
.trim()
.isLength({ max }).withMessage(`${field} must be at most ${max} characters`),
slug: (field) =>
body(field)
.optional()
.trim()
.matches(/^[a-z0-9_-]+$/i).withMessage(`${field} can only contain letters, numbers, dashes, underscores`),
email: (field) =>
body(field)
.trim()
.isEmail().withMessage('Must be a valid email')
.normalizeEmail(),
optionalEmail: (field) =>
body(field)
.optional()
.trim()
.isEmail().withMessage('Must be a valid email')
.normalizeEmail(),
enum: (field, values) =>
body(field)
.optional()
.isIn(values).withMessage(`${field} must be one of: ${values.join(', ')}`),
boolean: (field) =>
body(field)
.optional()
.isBoolean().withMessage(`${field} must be a boolean`),
integer: (field, min, max) => {
let validator = body(field).optional().isInt();
if (min !== undefined) validator = validator.custom(val => val >= min).withMessage(`${field} must be at least ${min}`);
if (max !== undefined) validator = validator.custom(val => val <= max).withMessage(`${field} must be at most ${max}`);
return validator;
},
pagination: () => [
query('page').optional().isInt({ min: 0 }).toInt(),
query('limit').optional().isInt({ min: 1, max: 100 }).toInt(),
],
url: (field) =>
body(field)
.optional()
.trim()
.isURL().withMessage(`${field} must be a valid URL`),
};
function createEntityValidation(entityConfig = {}) {
const { fields = [], requiredFields = [] } = entityConfig;
const fieldValidators = fields.map(field => {
if (requiredFields.includes(field.name)) {
return validators.requiredString(`data.${field.name}`, field.min || 1, field.max || 255);
}
return validators.optionalString(`data.${field.name}`, field.max || 255);
});
return {
create: [...fieldValidators, handleValidationErrors],
update: [validators.uuid('id'), ...fieldValidators, handleValidationErrors],
delete: [validators.uuid('id'), handleValidationErrors],
get: [validators.uuid('id'), handleValidationErrors],
list: [...validators.pagination(), handleValidationErrors],
};
}
module.exports = { handleValidationErrors, validators, createEntityValidation };

View File

@ -1,22 +1,6 @@
const express = require('express');
const Access_logsService = require('../services/access_logs');
const Access_logsDBApi = require('../db/api/access_logs');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const { parse } = require('json2csv');
const {
checkCrudPermissions,
} = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('access_logs'));
const { createEntityRouter } = require('../factories/router.factory');
/**
* @swagger
@ -25,20 +9,12 @@ router.use(checkCrudPermissions('access_logs'));
* Access_logs:
* type: object
* properties:
* path:
* type: string
* default: path
* ip_address:
* type: string
* default: ip_address
* user_agent:
* type: string
* default: user_agent
*
*/
/**
@ -56,7 +32,6 @@ router.use(checkCrudPermissions('access_logs'));
* - bearerAuth: []
* tags: [Access_logs]
* summary: Add new item
* description: Add new item
* requestBody:
* required: true
* content:
@ -64,73 +39,28 @@ router.use(checkCrudPermissions('access_logs'));
* schema:
* properties:
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Access_logs"
* responses:
* 200:
* description: The item was successfully added
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Access_logs"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*/
router.post('/', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Access_logsService.create(req.body.data, req.currentUser, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/budgets/bulk-import:
* post:
* get:
* security:
* - bearerAuth: []
* tags: [Access_logs]
* summary: Bulk import items
* description: Bulk import items
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated items
* type: array
* items:
* $ref: "#/components/schemas/Access_logs"
* summary: Get all access_logs
* responses:
* 200:
* description: The items were successfully imported
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Access_logs"
* description: Access_logs list successfully received
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*
*/
router.post('/bulk-import', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Access_logsService.bulkImport(req, res, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
@ -139,281 +69,67 @@ router.post('/bulk-import', wrapAsync(async (req, res) => {
* security:
* - bearerAuth: []
* tags: [Access_logs]
* summary: Update the data of the selected item
* description: Update the data of the selected item
* summary: Update the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to update
* required: true
* schema:
* type: string
* requestBody:
* description: Set new item data
* required: true
* content:
* application/json:
* schema:
* properties:
* id:
* description: ID of the updated item
* type: string
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Access_logs"
* required:
* - id
* responses:
* 200:
* description: The item data was successfully updated
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Access_logs"
* 400:
* description: Invalid ID supplied
* description: The item was successfully updated
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.put('/:id', wrapAsync(async (req, res) => {
await Access_logsService.update(req.body.data, req.body.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/access_logs/{id}:
* delete:
* security:
* - bearerAuth: []
* tags: [Access_logs]
* summary: Delete the selected item
* description: Delete the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to delete
* required: true
* schema:
* type: string
* responses:
* 200:
* description: The item was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Access_logs"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.delete('/:id', wrapAsync(async (req, res) => {
await Access_logsService.remove(req.params.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/access_logs/deleteByIds:
* post:
* security:
* - bearerAuth: []
* tags: [Access_logs]
* summary: Delete the selected item list
* description: Delete the selected item list
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* ids:
* description: IDs of the updated items
* type: array
* responses:
* 200:
* description: The items was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Access_logs"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Items not found
* 500:
* description: Some server error
*/
router.post('/deleteByIds', wrapAsync(async (req, res) => {
await Access_logsService.deleteByIds(req.body.data, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/access_logs:
* get:
* security:
* - bearerAuth: []
* tags: [Access_logs]
* summary: Get all access_logs
* description: Get all access_logs
* responses:
* 200:
* description: Access_logs list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Access_logs"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/', wrapAsync(async (req, res) => {
const filetype = req.query.filetype
const currentUser = req.currentUser;
const payload = await Access_logsDBApi.findAll(
req.query, { currentUser }
);
if (filetype && filetype === 'csv') {
const fields = ['id','path','ip_address','user_agent',
'accessed_at',
];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment(csv);
res.send(csv)
} catch (err) {
console.error(err);
}
} else {
res.status(200).send(payload);
}
}));
/**
* @swagger
* /api/access_logs/count:
* get:
* security:
* - bearerAuth: []
* tags: [Access_logs]
* summary: Count all access_logs
* description: Count all access_logs
* responses:
* 200:
* description: Access_logs count successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Access_logs"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/count', wrapAsync(async (req, res) => {
const currentUser = req.currentUser;
const payload = await Access_logsDBApi.findAll(
req.query,
null,
{ countOnly: true, currentUser }
);
res.status(200).send(payload);
}));
/**
* @swagger
* /api/access_logs/autocomplete:
* get:
* security:
* - bearerAuth: []
* tags: [Access_logs]
* summary: Find all access_logs that match search criteria
* description: Find all access_logs that match search criteria
* responses:
* 200:
* description: Access_logs list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Access_logs"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/autocomplete', async (req, res) => {
const payload = await Access_logsDBApi.findAllAutocomplete(
req.query.query,
req.query.limit,
req.query.offset,
);
res.status(200).send(payload);
});
/**
* @swagger
* /api/access_logs/{id}:
* get:
* security:
* - bearerAuth: []
* tags: [Access_logs]
* summary: Get selected item
* description: Get selected item
* parameters:
* - in: path
* name: id
* description: ID of item to get
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Selected item successfully received
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Access_logs"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
@ -421,16 +137,5 @@ router.get('/autocomplete', async (req, res) => {
* 500:
* description: Some server error
*/
router.get('/:id', wrapAsync(async (req, res) => {
const payload = await Access_logsDBApi.findBy(
{ id: req.params.id },
);
res.status(200).send(payload);
}));
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;
module.exports = createEntityRouter('access_logs', Access_logsService, Access_logsDBApi);

View File

@ -1,22 +1,6 @@
const express = require('express');
const Asset_variantsService = require('../services/asset_variants');
const Asset_variantsDBApi = require('../db/api/asset_variants');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const { parse } = require('json2csv');
const {
checkCrudPermissions,
} = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('asset_variants'));
const { createEntityRouter } = require('../factories/router.factory');
/**
* @swagger
@ -25,23 +9,14 @@ router.use(checkCrudPermissions('asset_variants'));
* Asset_variants:
* type: object
* properties:
* cdn_url:
* type: string
* default: cdn_url
* width_px:
* type: integer
* format: int64
* height_px:
* type: integer
* format: int64
* size_mb:
* type: integer
* format: int64
*
* type: number
*/
/**
@ -59,7 +34,6 @@ router.use(checkCrudPermissions('asset_variants'));
* - bearerAuth: []
* tags: [Asset_variants]
* summary: Add new item
* description: Add new item
* requestBody:
* required: true
* content:
@ -67,73 +41,28 @@ router.use(checkCrudPermissions('asset_variants'));
* schema:
* properties:
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Asset_variants"
* responses:
* 200:
* description: The item was successfully added
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Asset_variants"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*/
router.post('/', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Asset_variantsService.create(req.body.data, req.currentUser, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/budgets/bulk-import:
* post:
* get:
* security:
* - bearerAuth: []
* tags: [Asset_variants]
* summary: Bulk import items
* description: Bulk import items
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated items
* type: array
* items:
* $ref: "#/components/schemas/Asset_variants"
* summary: Get all asset variants
* responses:
* 200:
* description: The items were successfully imported
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Asset_variants"
* description: Asset_variants list successfully received
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*
*/
router.post('/bulk-import', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Asset_variantsService.bulkImport(req, res, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
@ -142,281 +71,67 @@ router.post('/bulk-import', wrapAsync(async (req, res) => {
* security:
* - bearerAuth: []
* tags: [Asset_variants]
* summary: Update the data of the selected item
* description: Update the data of the selected item
* summary: Update the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to update
* required: true
* schema:
* type: string
* requestBody:
* description: Set new item data
* required: true
* content:
* application/json:
* schema:
* properties:
* id:
* description: ID of the updated item
* type: string
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Asset_variants"
* required:
* - id
* responses:
* 200:
* description: The item data was successfully updated
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Asset_variants"
* 400:
* description: Invalid ID supplied
* description: The item was successfully updated
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.put('/:id', wrapAsync(async (req, res) => {
await Asset_variantsService.update(req.body.data, req.body.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/asset_variants/{id}:
* delete:
* security:
* - bearerAuth: []
* tags: [Asset_variants]
* summary: Delete the selected item
* description: Delete the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to delete
* required: true
* schema:
* type: string
* responses:
* 200:
* description: The item was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Asset_variants"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.delete('/:id', wrapAsync(async (req, res) => {
await Asset_variantsService.remove(req.params.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/asset_variants/deleteByIds:
* post:
* security:
* - bearerAuth: []
* tags: [Asset_variants]
* summary: Delete the selected item list
* description: Delete the selected item list
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* ids:
* description: IDs of the updated items
* type: array
* responses:
* 200:
* description: The items was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Asset_variants"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Items not found
* 500:
* description: Some server error
*/
router.post('/deleteByIds', wrapAsync(async (req, res) => {
await Asset_variantsService.deleteByIds(req.body.data, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/asset_variants:
* get:
* security:
* - bearerAuth: []
* tags: [Asset_variants]
* summary: Get all asset_variants
* description: Get all asset_variants
* responses:
* 200:
* description: Asset_variants list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Asset_variants"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/', wrapAsync(async (req, res) => {
const filetype = req.query.filetype
const currentUser = req.currentUser;
const payload = await Asset_variantsDBApi.findAll(
req.query, { currentUser }
);
if (filetype && filetype === 'csv') {
const fields = ['id','cdn_url',
'width_px','height_px',
'size_mb',
];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment(csv);
res.send(csv)
} catch (err) {
console.error(err);
}
} else {
res.status(200).send(payload);
}
}));
/**
* @swagger
* /api/asset_variants/count:
* get:
* security:
* - bearerAuth: []
* tags: [Asset_variants]
* summary: Count all asset_variants
* description: Count all asset_variants
* responses:
* 200:
* description: Asset_variants count successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Asset_variants"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/count', wrapAsync(async (req, res) => {
const currentUser = req.currentUser;
const payload = await Asset_variantsDBApi.findAll(
req.query,
null,
{ countOnly: true, currentUser }
);
res.status(200).send(payload);
}));
/**
* @swagger
* /api/asset_variants/autocomplete:
* get:
* security:
* - bearerAuth: []
* tags: [Asset_variants]
* summary: Find all asset_variants that match search criteria
* description: Find all asset_variants that match search criteria
* responses:
* 200:
* description: Asset_variants list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Asset_variants"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/autocomplete', async (req, res) => {
const payload = await Asset_variantsDBApi.findAllAutocomplete(
req.query.query,
req.query.limit,
req.query.offset,
);
res.status(200).send(payload);
});
/**
* @swagger
* /api/asset_variants/{id}:
* get:
* security:
* - bearerAuth: []
* tags: [Asset_variants]
* summary: Get selected item
* description: Get selected item
* parameters:
* - in: path
* name: id
* description: ID of item to get
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Selected item successfully received
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Asset_variants"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
@ -424,16 +139,5 @@ router.get('/autocomplete', async (req, res) => {
* 500:
* description: Some server error
*/
router.get('/:id', wrapAsync(async (req, res) => {
const payload = await Asset_variantsDBApi.findBy(
{ id: req.params.id },
);
res.status(200).send(payload);
}));
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;
module.exports = createEntityRouter('asset_variants', Asset_variantsService, Asset_variantsDBApi);

View File

@ -1,22 +1,6 @@
const express = require('express');
const AssetsService = require('../services/assets');
const AssetsDBApi = require('../db/api/assets');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const { parse } = require('json2csv');
const {
checkCrudPermissions,
} = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('assets'));
const { createEntityRouter } = require('../factories/router.factory');
/**
* @swagger
@ -25,38 +9,24 @@ router.use(checkCrudPermissions('assets'));
* Assets:
* type: object
* properties:
* name:
* type: string
* default: name
* cdn_url:
* type: string
* default: cdn_url
* storage_key:
* type: string
* default: storage_key
* mime_type:
* type: string
* default: mime_type
* checksum:
* type: string
* default: checksum
* width_px:
* type: integer
* format: int64
* height_px:
* type: integer
* format: int64
* size_mb:
* type: integer
* format: int64
* type: number
* duration_sec:
* type: integer
* format: int64
*
* type: number
*/
/**
@ -74,7 +44,6 @@ router.use(checkCrudPermissions('assets'));
* - bearerAuth: []
* tags: [Assets]
* summary: Add new item
* description: Add new item
* requestBody:
* required: true
* content:
@ -82,73 +51,28 @@ router.use(checkCrudPermissions('assets'));
* schema:
* properties:
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Assets"
* responses:
* 200:
* description: The item was successfully added
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Assets"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*/
router.post('/', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await AssetsService.create(req.body.data, req.currentUser, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/budgets/bulk-import:
* post:
* get:
* security:
* - bearerAuth: []
* tags: [Assets]
* summary: Bulk import items
* description: Bulk import items
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated items
* type: array
* items:
* $ref: "#/components/schemas/Assets"
* summary: Get all assets
* responses:
* 200:
* description: The items were successfully imported
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Assets"
* description: Assets list successfully received
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*
*/
router.post('/bulk-import', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await AssetsService.bulkImport(req, res, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
@ -157,281 +81,67 @@ router.post('/bulk-import', wrapAsync(async (req, res) => {
* security:
* - bearerAuth: []
* tags: [Assets]
* summary: Update the data of the selected item
* description: Update the data of the selected item
* summary: Update the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to update
* required: true
* schema:
* type: string
* requestBody:
* description: Set new item data
* required: true
* content:
* application/json:
* schema:
* properties:
* id:
* description: ID of the updated item
* type: string
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Assets"
* required:
* - id
* responses:
* 200:
* description: The item data was successfully updated
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Assets"
* 400:
* description: Invalid ID supplied
* description: The item was successfully updated
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.put('/:id', wrapAsync(async (req, res) => {
await AssetsService.update(req.body.data, req.body.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/assets/{id}:
* delete:
* security:
* - bearerAuth: []
* tags: [Assets]
* summary: Delete the selected item
* description: Delete the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to delete
* required: true
* schema:
* type: string
* responses:
* 200:
* description: The item was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Assets"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.delete('/:id', wrapAsync(async (req, res) => {
await AssetsService.remove(req.params.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/assets/deleteByIds:
* post:
* security:
* - bearerAuth: []
* tags: [Assets]
* summary: Delete the selected item list
* description: Delete the selected item list
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* ids:
* description: IDs of the updated items
* type: array
* responses:
* 200:
* description: The items was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Assets"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Items not found
* 500:
* description: Some server error
*/
router.post('/deleteByIds', wrapAsync(async (req, res) => {
await AssetsService.deleteByIds(req.body.data, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/assets:
* get:
* security:
* - bearerAuth: []
* tags: [Assets]
* summary: Get all assets
* description: Get all assets
* responses:
* 200:
* description: Assets list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Assets"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/', wrapAsync(async (req, res) => {
const filetype = req.query.filetype
const currentUser = req.currentUser;
const payload = await AssetsDBApi.findAll(
req.query, { currentUser }
);
if (filetype && filetype === 'csv') {
const fields = ['id','name','cdn_url','storage_key','mime_type','checksum',
'width_px','height_px',
'size_mb','duration_sec',
'deleted_at_time',
];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment(csv);
res.send(csv)
} catch (err) {
console.error(err);
}
} else {
res.status(200).send(payload);
}
}));
/**
* @swagger
* /api/assets/count:
* get:
* security:
* - bearerAuth: []
* tags: [Assets]
* summary: Count all assets
* description: Count all assets
* responses:
* 200:
* description: Assets count successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Assets"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/count', wrapAsync(async (req, res) => {
const currentUser = req.currentUser;
const payload = await AssetsDBApi.findAll(
req.query,
null,
{ countOnly: true, currentUser }
);
res.status(200).send(payload);
}));
/**
* @swagger
* /api/assets/autocomplete:
* get:
* security:
* - bearerAuth: []
* tags: [Assets]
* summary: Find all assets that match search criteria
* description: Find all assets that match search criteria
* responses:
* 200:
* description: Assets list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Assets"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/autocomplete', async (req, res) => {
const payload = await AssetsDBApi.findAllAutocomplete(
req.query.query,
req.query.limit,
req.query.offset,
);
res.status(200).send(payload);
});
/**
* @swagger
* /api/assets/{id}:
* get:
* security:
* - bearerAuth: []
* tags: [Assets]
* summary: Get selected item
* description: Get selected item
* parameters:
* - in: path
* name: id
* description: ID of item to get
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Selected item successfully received
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Assets"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
@ -439,16 +149,5 @@ router.get('/autocomplete', async (req, res) => {
* 500:
* description: Some server error
*/
router.get('/:id', wrapAsync(async (req, res) => {
const payload = await AssetsDBApi.findBy(
{ id: req.params.id },
);
res.status(200).send(payload);
}));
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;
module.exports = createEntityRouter('assets', AssetsService, AssetsDBApi);

View File

@ -1,22 +1,6 @@
const express = require('express');
const Page_elementsService = require('../services/page_elements');
const Page_elementsDBApi = require('../db/api/page_elements');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const { parse } = require('json2csv');
const {
checkCrudPermissions,
} = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('page_elements'));
const { createEntityRouter } = require('../factories/router.factory');
/**
* @swagger
@ -25,38 +9,24 @@ router.use(checkCrudPermissions('page_elements'));
* Page_elements:
* type: object
* properties:
* name:
* type: string
* default: name
* style_json:
* type: string
* default: style_json
* content_json:
* type: string
* default: content_json
* sort_order:
* type: integer
* format: int64
* x_percent:
* type: integer
* format: int64
* type: number
* y_percent:
* type: integer
* format: int64
* type: number
* width_percent:
* type: integer
* format: int64
* type: number
* height_percent:
* type: integer
* format: int64
* type: number
* rotation_deg:
* type: integer
* format: int64
*
* type: number
*/
/**
@ -74,7 +44,6 @@ router.use(checkCrudPermissions('page_elements'));
* - bearerAuth: []
* tags: [Page_elements]
* summary: Add new item
* description: Add new item
* requestBody:
* required: true
* content:
@ -82,73 +51,28 @@ router.use(checkCrudPermissions('page_elements'));
* schema:
* properties:
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Page_elements"
* responses:
* 200:
* description: The item was successfully added
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Page_elements"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*/
router.post('/', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Page_elementsService.create(req.body.data, req.currentUser, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/budgets/bulk-import:
* post:
* get:
* security:
* - bearerAuth: []
* tags: [Page_elements]
* summary: Bulk import items
* description: Bulk import items
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated items
* type: array
* items:
* $ref: "#/components/schemas/Page_elements"
* summary: Get all page_elements
* responses:
* 200:
* description: The items were successfully imported
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Page_elements"
* description: Page_elements list successfully received
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*
*/
router.post('/bulk-import', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Page_elementsService.bulkImport(req, res, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
@ -157,283 +81,67 @@ router.post('/bulk-import', wrapAsync(async (req, res) => {
* security:
* - bearerAuth: []
* tags: [Page_elements]
* summary: Update the data of the selected item
* description: Update the data of the selected item
* summary: Update the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to update
* required: true
* schema:
* type: string
* requestBody:
* description: Set new item data
* required: true
* content:
* application/json:
* schema:
* properties:
* id:
* description: ID of the updated item
* type: string
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Page_elements"
* required:
* - id
* responses:
* 200:
* description: The item data was successfully updated
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Page_elements"
* 400:
* description: Invalid ID supplied
* description: The item was successfully updated
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.put('/:id', wrapAsync(async (req, res) => {
await Page_elementsService.update(req.body.data, req.body.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/page_elements/{id}:
* delete:
* security:
* - bearerAuth: []
* tags: [Page_elements]
* summary: Delete the selected item
* description: Delete the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to delete
* required: true
* schema:
* type: string
* responses:
* 200:
* description: The item was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Page_elements"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.delete('/:id', wrapAsync(async (req, res) => {
await Page_elementsService.remove(req.params.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/page_elements/deleteByIds:
* post:
* security:
* - bearerAuth: []
* tags: [Page_elements]
* summary: Delete the selected item list
* description: Delete the selected item list
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* ids:
* description: IDs of the updated items
* type: array
* responses:
* 200:
* description: The items was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Page_elements"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Items not found
* 500:
* description: Some server error
*/
router.post('/deleteByIds', wrapAsync(async (req, res) => {
await Page_elementsService.deleteByIds(req.body.data, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/page_elements:
* get:
* security:
* - bearerAuth: []
* tags: [Page_elements]
* summary: Get all page_elements
* description: Get all page_elements
* responses:
* 200:
* description: Page_elements list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Page_elements"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/', wrapAsync(async (req, res) => {
const filetype = req.query.filetype
const currentUser = req.currentUser;
const runtimeContext = req.runtimeContext;
const payload = await Page_elementsDBApi.findAll(
req.query, { currentUser, runtimeContext }
);
if (filetype && filetype === 'csv') {
const fields = ['id','name','style_json','content_json',
'sort_order',
'x_percent','y_percent','width_percent','height_percent','rotation_deg',
];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment(csv);
res.send(csv)
} catch (err) {
console.error(err);
}
} else {
res.status(200).send(payload);
}
}));
/**
* @swagger
* /api/page_elements/count:
* get:
* security:
* - bearerAuth: []
* tags: [Page_elements]
* summary: Count all page_elements
* description: Count all page_elements
* responses:
* 200:
* description: Page_elements count successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Page_elements"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/count', wrapAsync(async (req, res) => {
const currentUser = req.currentUser;
const runtimeContext = req.runtimeContext;
const payload = await Page_elementsDBApi.findAll(
req.query,
null,
{ countOnly: true, currentUser, runtimeContext }
);
res.status(200).send(payload);
}));
/**
* @swagger
* /api/page_elements/autocomplete:
* get:
* security:
* - bearerAuth: []
* tags: [Page_elements]
* summary: Find all page_elements that match search criteria
* description: Find all page_elements that match search criteria
* responses:
* 200:
* description: Page_elements list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Page_elements"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/autocomplete', async (req, res) => {
const payload = await Page_elementsDBApi.findAllAutocomplete(
req.query.query,
req.query.limit,
req.query.offset,
);
res.status(200).send(payload);
});
/**
* @swagger
* /api/page_elements/{id}:
* get:
* security:
* - bearerAuth: []
* tags: [Page_elements]
* summary: Get selected item
* description: Get selected item
* parameters:
* - in: path
* name: id
* description: ID of item to get
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Selected item successfully received
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Page_elements"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
@ -441,18 +149,5 @@ router.get('/autocomplete', async (req, res) => {
* 500:
* description: Some server error
*/
router.get('/:id', wrapAsync(async (req, res) => {
const runtimeContext = req.runtimeContext;
const payload = await Page_elementsDBApi.findBy(
{ id: req.params.id },
{ runtimeContext },
);
res.status(200).send(payload);
}));
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;
module.exports = createEntityRouter('page_elements', Page_elementsService, Page_elementsDBApi);

View File

@ -1,22 +1,6 @@
const express = require('express');
const Page_linksService = require('../services/page_links');
const Page_linksDBApi = require('../db/api/page_links');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const { parse } = require('json2csv');
const {
checkCrudPermissions,
} = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('page_links'));
const { createEntityRouter } = require('../factories/router.factory');
/**
* @swagger
@ -25,17 +9,10 @@ router.use(checkCrudPermissions('page_links'));
* Page_links:
* type: object
* properties:
* external_url:
* type: string
* default: external_url
* trigger_selector:
* type: string
* default: trigger_selector
*
*/
/**
@ -53,7 +30,6 @@ router.use(checkCrudPermissions('page_links'));
* - bearerAuth: []
* tags: [Page_links]
* summary: Add new item
* description: Add new item
* requestBody:
* required: true
* content:
@ -61,73 +37,28 @@ router.use(checkCrudPermissions('page_links'));
* schema:
* properties:
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Page_links"
* responses:
* 200:
* description: The item was successfully added
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Page_links"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*/
router.post('/', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Page_linksService.create(req.body.data, req.currentUser, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/budgets/bulk-import:
* post:
* get:
* security:
* - bearerAuth: []
* tags: [Page_links]
* summary: Bulk import items
* description: Bulk import items
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated items
* type: array
* items:
* $ref: "#/components/schemas/Page_links"
* summary: Get all page_links
* responses:
* 200:
* description: The items were successfully imported
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Page_links"
* description: Page_links list successfully received
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*
*/
router.post('/bulk-import', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Page_linksService.bulkImport(req, res, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
@ -136,283 +67,67 @@ router.post('/bulk-import', wrapAsync(async (req, res) => {
* security:
* - bearerAuth: []
* tags: [Page_links]
* summary: Update the data of the selected item
* description: Update the data of the selected item
* summary: Update the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to update
* required: true
* schema:
* type: string
* requestBody:
* description: Set new item data
* required: true
* content:
* application/json:
* schema:
* properties:
* id:
* description: ID of the updated item
* type: string
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Page_links"
* required:
* - id
* responses:
* 200:
* description: The item data was successfully updated
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Page_links"
* 400:
* description: Invalid ID supplied
* description: The item was successfully updated
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.put('/:id', wrapAsync(async (req, res) => {
await Page_linksService.update(req.body.data, req.body.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/page_links/{id}:
* delete:
* security:
* - bearerAuth: []
* tags: [Page_links]
* summary: Delete the selected item
* description: Delete the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to delete
* required: true
* schema:
* type: string
* responses:
* 200:
* description: The item was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Page_links"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.delete('/:id', wrapAsync(async (req, res) => {
await Page_linksService.remove(req.params.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/page_links/deleteByIds:
* post:
* security:
* - bearerAuth: []
* tags: [Page_links]
* summary: Delete the selected item list
* description: Delete the selected item list
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* ids:
* description: IDs of the updated items
* type: array
* responses:
* 200:
* description: The items was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Page_links"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Items not found
* 500:
* description: Some server error
*/
router.post('/deleteByIds', wrapAsync(async (req, res) => {
await Page_linksService.deleteByIds(req.body.data, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/page_links:
* get:
* security:
* - bearerAuth: []
* tags: [Page_links]
* summary: Get all page_links
* description: Get all page_links
* responses:
* 200:
* description: Page_links list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Page_links"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/', wrapAsync(async (req, res) => {
const filetype = req.query.filetype
const currentUser = req.currentUser;
const runtimeContext = req.runtimeContext;
const payload = await Page_linksDBApi.findAll(
req.query, { currentUser, runtimeContext }
);
if (filetype && filetype === 'csv') {
const fields = ['id','external_url','trigger_selector',
];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment(csv);
res.send(csv)
} catch (err) {
console.error(err);
}
} else {
res.status(200).send(payload);
}
}));
/**
* @swagger
* /api/page_links/count:
* get:
* security:
* - bearerAuth: []
* tags: [Page_links]
* summary: Count all page_links
* description: Count all page_links
* responses:
* 200:
* description: Page_links count successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Page_links"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/count', wrapAsync(async (req, res) => {
const currentUser = req.currentUser;
const runtimeContext = req.runtimeContext;
const payload = await Page_linksDBApi.findAll(
req.query,
null,
{ countOnly: true, currentUser, runtimeContext }
);
res.status(200).send(payload);
}));
/**
* @swagger
* /api/page_links/autocomplete:
* get:
* security:
* - bearerAuth: []
* tags: [Page_links]
* summary: Find all page_links that match search criteria
* description: Find all page_links that match search criteria
* responses:
* 200:
* description: Page_links list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Page_links"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/autocomplete', async (req, res) => {
const payload = await Page_linksDBApi.findAllAutocomplete(
req.query.query,
req.query.limit,
req.query.offset,
);
res.status(200).send(payload);
});
/**
* @swagger
* /api/page_links/{id}:
* get:
* security:
* - bearerAuth: []
* tags: [Page_links]
* summary: Get selected item
* description: Get selected item
* parameters:
* - in: path
* name: id
* description: ID of item to get
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Selected item successfully received
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Page_links"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
@ -420,18 +135,5 @@ router.get('/autocomplete', async (req, res) => {
* 500:
* description: Some server error
*/
router.get('/:id', wrapAsync(async (req, res) => {
const runtimeContext = req.runtimeContext;
const payload = await Page_linksDBApi.findBy(
{ id: req.params.id },
{ runtimeContext },
);
res.status(200).send(payload);
}));
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;
module.exports = createEntityRouter('page_links', Page_linksService, Page_linksDBApi);

View File

@ -1,22 +1,6 @@
const express = require('express');
const PermissionsService = require('../services/permissions');
const PermissionsDBApi = require('../db/api/permissions');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const { parse } = require('json2csv');
const {
checkCrudPermissions,
} = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('permissions'));
const { createEntityRouter } = require('../factories/router.factory');
/**
* @swagger
@ -25,13 +9,9 @@ router.use(checkCrudPermissions('permissions'));
* Permissions:
* type: object
* properties:
* name:
* type: string
* default: name
*/
/**
@ -73,57 +53,28 @@ router.use(checkCrudPermissions('permissions'));
* description: Invalid input data
* 500:
* description: Some server error
*/
router.post('/', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await PermissionsService.create(req.body.data, req.currentUser, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/budgets/bulk-import:
* post:
* get:
* security:
* - bearerAuth: []
* tags: [Permissions]
* summary: Bulk import items
* description: Bulk import items
* requestBody:
* required: true
* summary: Get all permissions
* description: Get all permissions
* responses:
* 200:
* description: Permissions list successfully received
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated items
* type: array
* items:
* $ref: "#/components/schemas/Permissions"
* responses:
* 200:
* description: The items were successfully imported
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Permissions"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 404:
* description: Data not found
* 500:
* description: Some server error
*
*/
router.post('/bulk-import', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await PermissionsService.bulkImport(req, res, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
@ -172,16 +123,6 @@ router.post('/bulk-import', wrapAsync(async (req, res) => {
* description: Item not found
* 500:
* description: Some server error
*/
router.put('/:id', wrapAsync(async (req, res) => {
await PermissionsService.update(req.body.data, req.body.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/permissions/{id}:
* delete:
* security:
* - bearerAuth: []
@ -210,181 +151,6 @@ router.put('/:id', wrapAsync(async (req, res) => {
* description: Item not found
* 500:
* description: Some server error
*/
router.delete('/:id', wrapAsync(async (req, res) => {
await PermissionsService.remove(req.params.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/permissions/deleteByIds:
* post:
* security:
* - bearerAuth: []
* tags: [Permissions]
* summary: Delete the selected item list
* description: Delete the selected item list
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* ids:
* description: IDs of the updated items
* type: array
* responses:
* 200:
* description: The items was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Permissions"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Items not found
* 500:
* description: Some server error
*/
router.post('/deleteByIds', wrapAsync(async (req, res) => {
await PermissionsService.deleteByIds(req.body.data, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/permissions:
* get:
* security:
* - bearerAuth: []
* tags: [Permissions]
* summary: Get all permissions
* description: Get all permissions
* responses:
* 200:
* description: Permissions list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Permissions"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/', wrapAsync(async (req, res) => {
const filetype = req.query.filetype
const currentUser = req.currentUser;
const payload = await PermissionsDBApi.findAll(
req.query, { currentUser }
);
if (filetype && filetype === 'csv') {
const fields = ['id','name',
];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment(csv);
res.send(csv)
} catch (err) {
console.error(err);
}
} else {
res.status(200).send(payload);
}
}));
/**
* @swagger
* /api/permissions/count:
* get:
* security:
* - bearerAuth: []
* tags: [Permissions]
* summary: Count all permissions
* description: Count all permissions
* responses:
* 200:
* description: Permissions count successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Permissions"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/count', wrapAsync(async (req, res) => {
const currentUser = req.currentUser;
const payload = await PermissionsDBApi.findAll(
req.query,
null,
{ countOnly: true, currentUser }
);
res.status(200).send(payload);
}));
/**
* @swagger
* /api/permissions/autocomplete:
* get:
* security:
* - bearerAuth: []
* tags: [Permissions]
* summary: Find all permissions that match search criteria
* description: Find all permissions that match search criteria
* responses:
* 200:
* description: Permissions list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Permissions"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/autocomplete', async (req, res) => {
const payload = await PermissionsDBApi.findAllAutocomplete(
req.query.query,
req.query.limit,
req.query.offset,
);
res.status(200).send(payload);
});
/**
* @swagger
* /api/permissions/{id}:
* get:
* security:
* - bearerAuth: []
@ -414,16 +180,5 @@ router.get('/autocomplete', async (req, res) => {
* 500:
* description: Some server error
*/
router.get('/:id', wrapAsync(async (req, res) => {
const payload = await PermissionsDBApi.findBy(
{ id: req.params.id },
);
res.status(200).send(payload);
}));
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;
module.exports = createEntityRouter('permissions', PermissionsService, PermissionsDBApi);

View File

@ -1,22 +1,6 @@
const express = require('express');
const Presigned_url_requestsService = require('../services/presigned_url_requests');
const Presigned_url_requestsDBApi = require('../db/api/presigned_url_requests');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const { parse } = require('json2csv');
const {
checkCrudPermissions,
} = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('presigned_url_requests'));
const { createEntityRouter } = require('../factories/router.factory');
/**
* @swagger
@ -25,24 +9,17 @@ router.use(checkCrudPermissions('presigned_url_requests'));
* Presigned_url_requests:
* type: object
* properties:
* requested_key:
* type: string
* default: requested_key
* mime_type:
* type: string
* default: mime_type
* status:
* type: string
* default: status
* requested_size_mb:
* type: integer
* format: int64
*
*
* type: number
* expires_at:
* type: string
* format: date-time
*/
/**
@ -60,7 +37,6 @@ router.use(checkCrudPermissions('presigned_url_requests'));
* - bearerAuth: []
* tags: [Presigned_url_requests]
* summary: Add new item
* description: Add new item
* requestBody:
* required: true
* content:
@ -68,73 +44,28 @@ router.use(checkCrudPermissions('presigned_url_requests'));
* schema:
* properties:
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Presigned_url_requests"
* responses:
* 200:
* description: The item was successfully added
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Presigned_url_requests"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*/
router.post('/', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Presigned_url_requestsService.create(req.body.data, req.currentUser, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/budgets/bulk-import:
* post:
* get:
* security:
* - bearerAuth: []
* tags: [Presigned_url_requests]
* summary: Bulk import items
* description: Bulk import items
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated items
* type: array
* items:
* $ref: "#/components/schemas/Presigned_url_requests"
* summary: Get all presigned_url_requests
* responses:
* 200:
* description: The items were successfully imported
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Presigned_url_requests"
* description: Presigned_url_requests list successfully received
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*
*/
router.post('/bulk-import', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Presigned_url_requestsService.bulkImport(req, res, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
@ -143,281 +74,67 @@ router.post('/bulk-import', wrapAsync(async (req, res) => {
* security:
* - bearerAuth: []
* tags: [Presigned_url_requests]
* summary: Update the data of the selected item
* description: Update the data of the selected item
* summary: Update the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to update
* required: true
* schema:
* type: string
* requestBody:
* description: Set new item data
* required: true
* content:
* application/json:
* schema:
* properties:
* id:
* description: ID of the updated item
* type: string
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Presigned_url_requests"
* required:
* - id
* responses:
* 200:
* description: The item data was successfully updated
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Presigned_url_requests"
* 400:
* description: Invalid ID supplied
* description: The item was successfully updated
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.put('/:id', wrapAsync(async (req, res) => {
await Presigned_url_requestsService.update(req.body.data, req.body.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/presigned_url_requests/{id}:
* delete:
* security:
* - bearerAuth: []
* tags: [Presigned_url_requests]
* summary: Delete the selected item
* description: Delete the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to delete
* required: true
* schema:
* type: string
* responses:
* 200:
* description: The item was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Presigned_url_requests"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.delete('/:id', wrapAsync(async (req, res) => {
await Presigned_url_requestsService.remove(req.params.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/presigned_url_requests/deleteByIds:
* post:
* security:
* - bearerAuth: []
* tags: [Presigned_url_requests]
* summary: Delete the selected item list
* description: Delete the selected item list
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* ids:
* description: IDs of the updated items
* type: array
* responses:
* 200:
* description: The items was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Presigned_url_requests"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Items not found
* 500:
* description: Some server error
*/
router.post('/deleteByIds', wrapAsync(async (req, res) => {
await Presigned_url_requestsService.deleteByIds(req.body.data, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/presigned_url_requests:
* get:
* security:
* - bearerAuth: []
* tags: [Presigned_url_requests]
* summary: Get all presigned_url_requests
* description: Get all presigned_url_requests
* responses:
* 200:
* description: Presigned_url_requests list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Presigned_url_requests"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/', wrapAsync(async (req, res) => {
const filetype = req.query.filetype
const currentUser = req.currentUser;
const payload = await Presigned_url_requestsDBApi.findAll(
req.query, { currentUser }
);
if (filetype && filetype === 'csv') {
const fields = ['id','requested_key','mime_type','status',
'requested_size_mb',
'expires_at',
];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment(csv);
res.send(csv)
} catch (err) {
console.error(err);
}
} else {
res.status(200).send(payload);
}
}));
/**
* @swagger
* /api/presigned_url_requests/count:
* get:
* security:
* - bearerAuth: []
* tags: [Presigned_url_requests]
* summary: Count all presigned_url_requests
* description: Count all presigned_url_requests
* responses:
* 200:
* description: Presigned_url_requests count successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Presigned_url_requests"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/count', wrapAsync(async (req, res) => {
const currentUser = req.currentUser;
const payload = await Presigned_url_requestsDBApi.findAll(
req.query,
null,
{ countOnly: true, currentUser }
);
res.status(200).send(payload);
}));
/**
* @swagger
* /api/presigned_url_requests/autocomplete:
* get:
* security:
* - bearerAuth: []
* tags: [Presigned_url_requests]
* summary: Find all presigned_url_requests that match search criteria
* description: Find all presigned_url_requests that match search criteria
* responses:
* 200:
* description: Presigned_url_requests list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Presigned_url_requests"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/autocomplete', async (req, res) => {
const payload = await Presigned_url_requestsDBApi.findAllAutocomplete(
req.query.query,
req.query.limit,
req.query.offset,
);
res.status(200).send(payload);
});
/**
* @swagger
* /api/presigned_url_requests/{id}:
* get:
* security:
* - bearerAuth: []
* tags: [Presigned_url_requests]
* summary: Get selected item
* description: Get selected item
* parameters:
* - in: path
* name: id
* description: ID of item to get
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Selected item successfully received
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Presigned_url_requests"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
@ -425,16 +142,5 @@ router.get('/autocomplete', async (req, res) => {
* 500:
* description: Some server error
*/
router.get('/:id', wrapAsync(async (req, res) => {
const payload = await Presigned_url_requestsDBApi.findBy(
{ id: req.params.id },
);
res.status(200).send(payload);
}));
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;
module.exports = createEntityRouter('presigned_url_requests', Presigned_url_requestsService, Presigned_url_requestsDBApi);

View File

@ -1,22 +1,6 @@
const express = require('express');
const Project_audio_tracksService = require('../services/project_audio_tracks');
const Project_audio_tracksDBApi = require('../db/api/project_audio_tracks');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const { parse } = require('json2csv');
const {
checkCrudPermissions,
} = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('project_audio_tracks'));
const { createEntityRouter } = require('../factories/router.factory');
/**
* @swagger
@ -25,29 +9,18 @@ router.use(checkCrudPermissions('project_audio_tracks'));
* Project_audio_tracks:
* type: object
* properties:
* source_key:
* type: string
* default: source_key
* name:
* type: string
* default: name
* slug:
* type: string
* default: slug
* url:
* type: string
* default: url
* sort_order:
* type: integer
* format: int64
* volume:
* type: integer
* format: int64
*
* type: number
*/
/**
@ -65,7 +38,6 @@ router.use(checkCrudPermissions('project_audio_tracks'));
* - bearerAuth: []
* tags: [Project_audio_tracks]
* summary: Add new item
* description: Add new item
* requestBody:
* required: true
* content:
@ -73,73 +45,28 @@ router.use(checkCrudPermissions('project_audio_tracks'));
* schema:
* properties:
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Project_audio_tracks"
* responses:
* 200:
* description: The item was successfully added
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Project_audio_tracks"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*/
router.post('/', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Project_audio_tracksService.create(req.body.data, req.currentUser, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/budgets/bulk-import:
* post:
* get:
* security:
* - bearerAuth: []
* tags: [Project_audio_tracks]
* summary: Bulk import items
* description: Bulk import items
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated items
* type: array
* items:
* $ref: "#/components/schemas/Project_audio_tracks"
* summary: Get all project_audio_tracks
* responses:
* 200:
* description: The items were successfully imported
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Project_audio_tracks"
* description: Project_audio_tracks list successfully received
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*
*/
router.post('/bulk-import', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Project_audio_tracksService.bulkImport(req, res, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
@ -148,283 +75,67 @@ router.post('/bulk-import', wrapAsync(async (req, res) => {
* security:
* - bearerAuth: []
* tags: [Project_audio_tracks]
* summary: Update the data of the selected item
* description: Update the data of the selected item
* summary: Update the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to update
* required: true
* schema:
* type: string
* requestBody:
* description: Set new item data
* required: true
* content:
* application/json:
* schema:
* properties:
* id:
* description: ID of the updated item
* type: string
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Project_audio_tracks"
* required:
* - id
* responses:
* 200:
* description: The item data was successfully updated
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Project_audio_tracks"
* 400:
* description: Invalid ID supplied
* description: The item was successfully updated
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.put('/:id', wrapAsync(async (req, res) => {
await Project_audio_tracksService.update(req.body.data, req.body.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/project_audio_tracks/{id}:
* delete:
* security:
* - bearerAuth: []
* tags: [Project_audio_tracks]
* summary: Delete the selected item
* description: Delete the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to delete
* required: true
* schema:
* type: string
* responses:
* 200:
* description: The item was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Project_audio_tracks"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.delete('/:id', wrapAsync(async (req, res) => {
await Project_audio_tracksService.remove(req.params.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/project_audio_tracks/deleteByIds:
* post:
* security:
* - bearerAuth: []
* tags: [Project_audio_tracks]
* summary: Delete the selected item list
* description: Delete the selected item list
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* ids:
* description: IDs of the updated items
* type: array
* responses:
* 200:
* description: The items was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Project_audio_tracks"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Items not found
* 500:
* description: Some server error
*/
router.post('/deleteByIds', wrapAsync(async (req, res) => {
await Project_audio_tracksService.deleteByIds(req.body.data, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/project_audio_tracks:
* get:
* security:
* - bearerAuth: []
* tags: [Project_audio_tracks]
* summary: Get all project_audio_tracks
* description: Get all project_audio_tracks
* responses:
* 200:
* description: Project_audio_tracks list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Project_audio_tracks"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/', wrapAsync(async (req, res) => {
const filetype = req.query.filetype
const currentUser = req.currentUser;
const runtimeContext = req.runtimeContext;
const payload = await Project_audio_tracksDBApi.findAll(
req.query, { currentUser, runtimeContext }
);
if (filetype && filetype === 'csv') {
const fields = ['id','source_key','name','slug','url',
'sort_order',
'volume',
];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment(csv);
res.send(csv)
} catch (err) {
console.error(err);
}
} else {
res.status(200).send(payload);
}
}));
/**
* @swagger
* /api/project_audio_tracks/count:
* get:
* security:
* - bearerAuth: []
* tags: [Project_audio_tracks]
* summary: Count all project_audio_tracks
* description: Count all project_audio_tracks
* responses:
* 200:
* description: Project_audio_tracks count successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Project_audio_tracks"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/count', wrapAsync(async (req, res) => {
const currentUser = req.currentUser;
const runtimeContext = req.runtimeContext;
const payload = await Project_audio_tracksDBApi.findAll(
req.query,
null,
{ countOnly: true, currentUser, runtimeContext }
);
res.status(200).send(payload);
}));
/**
* @swagger
* /api/project_audio_tracks/autocomplete:
* get:
* security:
* - bearerAuth: []
* tags: [Project_audio_tracks]
* summary: Find all project_audio_tracks that match search criteria
* description: Find all project_audio_tracks that match search criteria
* responses:
* 200:
* description: Project_audio_tracks list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Project_audio_tracks"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/autocomplete', async (req, res) => {
const payload = await Project_audio_tracksDBApi.findAllAutocomplete(
req.query.query,
req.query.limit,
req.query.offset,
);
res.status(200).send(payload);
});
/**
* @swagger
* /api/project_audio_tracks/{id}:
* get:
* security:
* - bearerAuth: []
* tags: [Project_audio_tracks]
* summary: Get selected item
* description: Get selected item
* parameters:
* - in: path
* name: id
* description: ID of item to get
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Selected item successfully received
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Project_audio_tracks"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
@ -432,18 +143,5 @@ router.get('/autocomplete', async (req, res) => {
* 500:
* description: Some server error
*/
router.get('/:id', wrapAsync(async (req, res) => {
const runtimeContext = req.runtimeContext;
const payload = await Project_audio_tracksDBApi.findBy(
{ id: req.params.id },
{ runtimeContext },
);
res.status(200).send(payload);
}));
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;
module.exports = createEntityRouter('project_audio_tracks', Project_audio_tracksService, Project_audio_tracksDBApi);

View File

@ -1,22 +1,6 @@
const express = require('express');
const Project_membershipsService = require('../services/project_memberships');
const Project_membershipsDBApi = require('../db/api/project_memberships');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const { parse } = require('json2csv');
const {
checkCrudPermissions,
} = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('project_memberships'));
const { createEntityRouter } = require('../factories/router.factory');
/**
* @swagger
@ -25,11 +9,12 @@ router.use(checkCrudPermissions('project_memberships'));
* Project_memberships:
* type: object
* properties:
*
* invited_at:
* type: string
* format: date-time
* accepted_at:
* type: string
* format: date-time
*/
/**
@ -47,7 +32,6 @@ router.use(checkCrudPermissions('project_memberships'));
* - bearerAuth: []
* tags: [Project_memberships]
* summary: Add new item
* description: Add new item
* requestBody:
* required: true
* content:
@ -55,73 +39,28 @@ router.use(checkCrudPermissions('project_memberships'));
* schema:
* properties:
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Project_memberships"
* responses:
* 200:
* description: The item was successfully added
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Project_memberships"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*/
router.post('/', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Project_membershipsService.create(req.body.data, req.currentUser, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/budgets/bulk-import:
* post:
* get:
* security:
* - bearerAuth: []
* tags: [Project_memberships]
* summary: Bulk import items
* description: Bulk import items
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated items
* type: array
* items:
* $ref: "#/components/schemas/Project_memberships"
* summary: Get all project_memberships
* responses:
* 200:
* description: The items were successfully imported
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Project_memberships"
* description: Project_memberships list successfully received
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*
*/
router.post('/bulk-import', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Project_membershipsService.bulkImport(req, res, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
@ -130,281 +69,67 @@ router.post('/bulk-import', wrapAsync(async (req, res) => {
* security:
* - bearerAuth: []
* tags: [Project_memberships]
* summary: Update the data of the selected item
* description: Update the data of the selected item
* summary: Update the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to update
* required: true
* schema:
* type: string
* requestBody:
* description: Set new item data
* required: true
* content:
* application/json:
* schema:
* properties:
* id:
* description: ID of the updated item
* type: string
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Project_memberships"
* required:
* - id
* responses:
* 200:
* description: The item data was successfully updated
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Project_memberships"
* 400:
* description: Invalid ID supplied
* description: The item was successfully updated
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.put('/:id', wrapAsync(async (req, res) => {
await Project_membershipsService.update(req.body.data, req.body.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/project_memberships/{id}:
* delete:
* security:
* - bearerAuth: []
* tags: [Project_memberships]
* summary: Delete the selected item
* description: Delete the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to delete
* required: true
* schema:
* type: string
* responses:
* 200:
* description: The item was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Project_memberships"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.delete('/:id', wrapAsync(async (req, res) => {
await Project_membershipsService.remove(req.params.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/project_memberships/deleteByIds:
* post:
* security:
* - bearerAuth: []
* tags: [Project_memberships]
* summary: Delete the selected item list
* description: Delete the selected item list
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* ids:
* description: IDs of the updated items
* type: array
* responses:
* 200:
* description: The items was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Project_memberships"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Items not found
* 500:
* description: Some server error
*/
router.post('/deleteByIds', wrapAsync(async (req, res) => {
await Project_membershipsService.deleteByIds(req.body.data, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/project_memberships:
* get:
* security:
* - bearerAuth: []
* tags: [Project_memberships]
* summary: Get all project_memberships
* description: Get all project_memberships
* responses:
* 200:
* description: Project_memberships list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Project_memberships"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/', wrapAsync(async (req, res) => {
const filetype = req.query.filetype
const currentUser = req.currentUser;
const payload = await Project_membershipsDBApi.findAll(
req.query, { currentUser }
);
if (filetype && filetype === 'csv') {
const fields = ['id',
'invited_at','accepted_at',
];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment(csv);
res.send(csv)
} catch (err) {
console.error(err);
}
} else {
res.status(200).send(payload);
}
}));
/**
* @swagger
* /api/project_memberships/count:
* get:
* security:
* - bearerAuth: []
* tags: [Project_memberships]
* summary: Count all project_memberships
* description: Count all project_memberships
* responses:
* 200:
* description: Project_memberships count successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Project_memberships"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/count', wrapAsync(async (req, res) => {
const currentUser = req.currentUser;
const payload = await Project_membershipsDBApi.findAll(
req.query,
null,
{ countOnly: true, currentUser }
);
res.status(200).send(payload);
}));
/**
* @swagger
* /api/project_memberships/autocomplete:
* get:
* security:
* - bearerAuth: []
* tags: [Project_memberships]
* summary: Find all project_memberships that match search criteria
* description: Find all project_memberships that match search criteria
* responses:
* 200:
* description: Project_memberships list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Project_memberships"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/autocomplete', async (req, res) => {
const payload = await Project_membershipsDBApi.findAllAutocomplete(
req.query.query,
req.query.limit,
req.query.offset,
);
res.status(200).send(payload);
});
/**
* @swagger
* /api/project_memberships/{id}:
* get:
* security:
* - bearerAuth: []
* tags: [Project_memberships]
* summary: Get selected item
* description: Get selected item
* parameters:
* - in: path
* name: id
* description: ID of item to get
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Selected item successfully received
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Project_memberships"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
@ -412,16 +137,5 @@ router.get('/autocomplete', async (req, res) => {
* 500:
* description: Some server error
*/
router.get('/:id', wrapAsync(async (req, res) => {
const payload = await Project_membershipsDBApi.findBy(
{ id: req.params.id },
);
res.status(200).send(payload);
}));
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;
module.exports = createEntityRouter('project_memberships', Project_membershipsService, Project_membershipsDBApi);

View File

@ -1,22 +1,6 @@
const express = require('express');
const Publish_eventsService = require('../services/publish_events');
const Publish_eventsDBApi = require('../db/api/publish_events');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const { parse } = require('json2csv');
const {
checkCrudPermissions,
} = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('publish_events'));
const { createEntityRouter } = require('../factories/router.factory');
/**
* @swagger
@ -25,25 +9,24 @@ router.use(checkCrudPermissions('publish_events'));
* Publish_events:
* type: object
* properties:
* title:
* type: string
* description:
* type: string
* error_message:
* type: string
* default: error_message
* pages_copied:
* type: integer
* format: int64
* transitions_copied:
* type: integer
* format: int64
* audios_copied:
* type: integer
* format: int64
*
*
*
* started_at:
* type: string
* format: date-time
* finished_at:
* type: string
* format: date-time
*/
/**
@ -61,7 +44,6 @@ router.use(checkCrudPermissions('publish_events'));
* - bearerAuth: []
* tags: [Publish_events]
* summary: Add new item
* description: Add new item
* requestBody:
* required: true
* content:
@ -69,73 +51,28 @@ router.use(checkCrudPermissions('publish_events'));
* schema:
* properties:
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Publish_events"
* responses:
* 200:
* description: The item was successfully added
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Publish_events"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*/
router.post('/', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Publish_eventsService.create(req.body.data, req.currentUser, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/budgets/bulk-import:
* post:
* get:
* security:
* - bearerAuth: []
* tags: [Publish_events]
* summary: Bulk import items
* description: Bulk import items
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated items
* type: array
* items:
* $ref: "#/components/schemas/Publish_events"
* summary: Get all publish_events
* responses:
* 200:
* description: The items were successfully imported
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Publish_events"
* description: Publish_events list successfully received
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*
*/
router.post('/bulk-import', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Publish_eventsService.bulkImport(req, res, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
@ -144,281 +81,67 @@ router.post('/bulk-import', wrapAsync(async (req, res) => {
* security:
* - bearerAuth: []
* tags: [Publish_events]
* summary: Update the data of the selected item
* description: Update the data of the selected item
* summary: Update the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to update
* required: true
* schema:
* type: string
* requestBody:
* description: Set new item data
* required: true
* content:
* application/json:
* schema:
* properties:
* id:
* description: ID of the updated item
* type: string
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Publish_events"
* required:
* - id
* responses:
* 200:
* description: The item data was successfully updated
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Publish_events"
* 400:
* description: Invalid ID supplied
* description: The item was successfully updated
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.put('/:id', wrapAsync(async (req, res) => {
await Publish_eventsService.update(req.body.data, req.body.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/publish_events/{id}:
* delete:
* security:
* - bearerAuth: []
* tags: [Publish_events]
* summary: Delete the selected item
* description: Delete the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to delete
* required: true
* schema:
* type: string
* responses:
* 200:
* description: The item was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Publish_events"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.delete('/:id', wrapAsync(async (req, res) => {
await Publish_eventsService.remove(req.params.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/publish_events/deleteByIds:
* post:
* security:
* - bearerAuth: []
* tags: [Publish_events]
* summary: Delete the selected item list
* description: Delete the selected item list
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* ids:
* description: IDs of the updated items
* type: array
* responses:
* 200:
* description: The items was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Publish_events"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Items not found
* 500:
* description: Some server error
*/
router.post('/deleteByIds', wrapAsync(async (req, res) => {
await Publish_eventsService.deleteByIds(req.body.data, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/publish_events:
* get:
* security:
* - bearerAuth: []
* tags: [Publish_events]
* summary: Get all publish_events
* description: Get all publish_events
* responses:
* 200:
* description: Publish_events list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Publish_events"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/', wrapAsync(async (req, res) => {
const filetype = req.query.filetype
const currentUser = req.currentUser;
const payload = await Publish_eventsDBApi.findAll(
req.query, { currentUser }
);
if (filetype && filetype === 'csv') {
const fields = ['id','title','description','error_message',
'pages_copied','transitions_copied','audios_copied',
'started_at','finished_at',
];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment(csv);
res.send(csv)
} catch (err) {
console.error(err);
}
} else {
res.status(200).send(payload);
}
}));
/**
* @swagger
* /api/publish_events/count:
* get:
* security:
* - bearerAuth: []
* tags: [Publish_events]
* summary: Count all publish_events
* description: Count all publish_events
* responses:
* 200:
* description: Publish_events count successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Publish_events"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/count', wrapAsync(async (req, res) => {
const currentUser = req.currentUser;
const payload = await Publish_eventsDBApi.findAll(
req.query,
null,
{ countOnly: true, currentUser }
);
res.status(200).send(payload);
}));
/**
* @swagger
* /api/publish_events/autocomplete:
* get:
* security:
* - bearerAuth: []
* tags: [Publish_events]
* summary: Find all publish_events that match search criteria
* description: Find all publish_events that match search criteria
* responses:
* 200:
* description: Publish_events list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Publish_events"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/autocomplete', async (req, res) => {
const payload = await Publish_eventsDBApi.findAllAutocomplete(
req.query.query,
req.query.limit,
req.query.offset,
);
res.status(200).send(payload);
});
/**
* @swagger
* /api/publish_events/{id}:
* get:
* security:
* - bearerAuth: []
* tags: [Publish_events]
* summary: Get selected item
* description: Get selected item
* parameters:
* - in: path
* name: id
* description: ID of item to get
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Selected item successfully received
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Publish_events"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
@ -426,16 +149,5 @@ router.get('/autocomplete', async (req, res) => {
* 500:
* description: Some server error
*/
router.get('/:id', wrapAsync(async (req, res) => {
const payload = await Publish_eventsDBApi.findBy(
{ id: req.params.id },
);
res.status(200).send(payload);
}));
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;
module.exports = createEntityRouter('publish_events', Publish_eventsService, Publish_eventsDBApi);

View File

@ -1,22 +1,6 @@
const express = require('express');
const Pwa_cachesService = require('../services/pwa_caches');
const Pwa_cachesDBApi = require('../db/api/pwa_caches');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const { parse } = require('json2csv');
const {
checkCrudPermissions,
} = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('pwa_caches'));
const { createEntityRouter } = require('../factories/router.factory');
/**
* @swagger
@ -25,20 +9,15 @@ router.use(checkCrudPermissions('pwa_caches'));
* Pwa_caches:
* type: object
* properties:
* cache_version:
* type: string
* default: cache_version
* manifest_json:
* type: string
* default: manifest_json
* asset_list_json:
* type: string
* default: asset_list_json
*
* generated_at:
* type: string
* format: date-time
*/
/**
@ -56,7 +35,6 @@ router.use(checkCrudPermissions('pwa_caches'));
* - bearerAuth: []
* tags: [Pwa_caches]
* summary: Add new item
* description: Add new item
* requestBody:
* required: true
* content:
@ -64,73 +42,28 @@ router.use(checkCrudPermissions('pwa_caches'));
* schema:
* properties:
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Pwa_caches"
* responses:
* 200:
* description: The item was successfully added
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Pwa_caches"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*/
router.post('/', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Pwa_cachesService.create(req.body.data, req.currentUser, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/budgets/bulk-import:
* post:
* get:
* security:
* - bearerAuth: []
* tags: [Pwa_caches]
* summary: Bulk import items
* description: Bulk import items
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated items
* type: array
* items:
* $ref: "#/components/schemas/Pwa_caches"
* summary: Get all pwa_caches
* responses:
* 200:
* description: The items were successfully imported
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Pwa_caches"
* description: Pwa_caches list successfully received
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*
*/
router.post('/bulk-import', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Pwa_cachesService.bulkImport(req, res, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
@ -139,281 +72,67 @@ router.post('/bulk-import', wrapAsync(async (req, res) => {
* security:
* - bearerAuth: []
* tags: [Pwa_caches]
* summary: Update the data of the selected item
* description: Update the data of the selected item
* summary: Update the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to update
* required: true
* schema:
* type: string
* requestBody:
* description: Set new item data
* required: true
* content:
* application/json:
* schema:
* properties:
* id:
* description: ID of the updated item
* type: string
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Pwa_caches"
* required:
* - id
* responses:
* 200:
* description: The item data was successfully updated
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Pwa_caches"
* 400:
* description: Invalid ID supplied
* description: The item was successfully updated
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.put('/:id', wrapAsync(async (req, res) => {
await Pwa_cachesService.update(req.body.data, req.body.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/pwa_caches/{id}:
* delete:
* security:
* - bearerAuth: []
* tags: [Pwa_caches]
* summary: Delete the selected item
* description: Delete the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to delete
* required: true
* schema:
* type: string
* responses:
* 200:
* description: The item was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Pwa_caches"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.delete('/:id', wrapAsync(async (req, res) => {
await Pwa_cachesService.remove(req.params.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/pwa_caches/deleteByIds:
* post:
* security:
* - bearerAuth: []
* tags: [Pwa_caches]
* summary: Delete the selected item list
* description: Delete the selected item list
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* ids:
* description: IDs of the updated items
* type: array
* responses:
* 200:
* description: The items was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Pwa_caches"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Items not found
* 500:
* description: Some server error
*/
router.post('/deleteByIds', wrapAsync(async (req, res) => {
await Pwa_cachesService.deleteByIds(req.body.data, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/pwa_caches:
* get:
* security:
* - bearerAuth: []
* tags: [Pwa_caches]
* summary: Get all pwa_caches
* description: Get all pwa_caches
* responses:
* 200:
* description: Pwa_caches list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Pwa_caches"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/', wrapAsync(async (req, res) => {
const filetype = req.query.filetype
const currentUser = req.currentUser;
const payload = await Pwa_cachesDBApi.findAll(
req.query, { currentUser }
);
if (filetype && filetype === 'csv') {
const fields = ['id','cache_version','manifest_json','asset_list_json',
'generated_at',
];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment(csv);
res.send(csv)
} catch (err) {
console.error(err);
}
} else {
res.status(200).send(payload);
}
}));
/**
* @swagger
* /api/pwa_caches/count:
* get:
* security:
* - bearerAuth: []
* tags: [Pwa_caches]
* summary: Count all pwa_caches
* description: Count all pwa_caches
* responses:
* 200:
* description: Pwa_caches count successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Pwa_caches"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/count', wrapAsync(async (req, res) => {
const currentUser = req.currentUser;
const payload = await Pwa_cachesDBApi.findAll(
req.query,
null,
{ countOnly: true, currentUser }
);
res.status(200).send(payload);
}));
/**
* @swagger
* /api/pwa_caches/autocomplete:
* get:
* security:
* - bearerAuth: []
* tags: [Pwa_caches]
* summary: Find all pwa_caches that match search criteria
* description: Find all pwa_caches that match search criteria
* responses:
* 200:
* description: Pwa_caches list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Pwa_caches"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/autocomplete', async (req, res) => {
const payload = await Pwa_cachesDBApi.findAllAutocomplete(
req.query.query,
req.query.limit,
req.query.offset,
);
res.status(200).send(payload);
});
/**
* @swagger
* /api/pwa_caches/{id}:
* get:
* security:
* - bearerAuth: []
* tags: [Pwa_caches]
* summary: Get selected item
* description: Get selected item
* parameters:
* - in: path
* name: id
* description: ID of item to get
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Selected item successfully received
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Pwa_caches"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
@ -421,16 +140,5 @@ router.get('/autocomplete', async (req, res) => {
* 500:
* description: Some server error
*/
router.get('/:id', wrapAsync(async (req, res) => {
const payload = await Pwa_cachesDBApi.findBy(
{ id: req.params.id },
);
res.status(200).send(payload);
}));
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;
module.exports = createEntityRouter('pwa_caches', Pwa_cachesService, Pwa_cachesDBApi);

View File

@ -1,22 +1,6 @@
const express = require('express');
const RolesService = require('../services/roles');
const RolesDBApi = require('../db/api/roles');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const { parse } = require('json2csv');
const {
checkCrudPermissions,
} = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('roles'));
const { createEntityRouter } = require('../factories/router.factory');
/**
* @swagger
@ -25,13 +9,9 @@ router.use(checkCrudPermissions('roles'));
* Roles:
* type: object
* properties:
* name:
* type: string
* default: name
*/
/**
@ -57,207 +37,16 @@ router.use(checkCrudPermissions('roles'));
* schema:
* properties:
* data:
* description: Data of the updated item
* description: Data of the item
* type: object
* $ref: "#/components/schemas/Roles"
* responses:
* 200:
* description: The item was successfully added
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Roles"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*/
router.post('/', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await RolesService.create(req.body.data, req.currentUser, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/budgets/bulk-import:
* post:
* security:
* - bearerAuth: []
* tags: [Roles]
* summary: Bulk import items
* description: Bulk import items
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated items
* type: array
* items:
* $ref: "#/components/schemas/Roles"
* responses:
* 200:
* description: The items were successfully imported
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Roles"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*
*/
router.post('/bulk-import', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await RolesService.bulkImport(req, res, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/roles/{id}:
* put:
* security:
* - bearerAuth: []
* tags: [Roles]
* summary: Update the data of the selected item
* description: Update the data of the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to update
* required: true
* schema:
* type: string
* requestBody:
* description: Set new item data
* required: true
* content:
* application/json:
* schema:
* properties:
* id:
* description: ID of the updated item
* type: string
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Roles"
* required:
* - id
* responses:
* 200:
* description: The item data was successfully updated
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Roles"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.put('/:id', wrapAsync(async (req, res) => {
await RolesService.update(req.body.data, req.body.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/roles/{id}:
* delete:
* security:
* - bearerAuth: []
* tags: [Roles]
* summary: Delete the selected item
* description: Delete the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to delete
* required: true
* schema:
* type: string
* responses:
* 200:
* description: The item was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Roles"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.delete('/:id', wrapAsync(async (req, res) => {
await RolesService.remove(req.params.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/roles/deleteByIds:
* post:
* security:
* - bearerAuth: []
* tags: [Roles]
* summary: Delete the selected item list
* description: Delete the selected item list
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* ids:
* description: IDs of the updated items
* type: array
* responses:
* 200:
* description: The items was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Roles"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Items not found
* 500:
* description: Some server error
*/
router.post('/deleteByIds', wrapAsync(async (req, res) => {
await RolesService.deleteByIds(req.body.data, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/roles:
* get:
* security:
* - bearerAuth: []
@ -267,146 +56,80 @@ router.post('/deleteByIds', wrapAsync(async (req, res) => {
* responses:
* 200:
* description: Roles list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Roles"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/', wrapAsync(async (req, res) => {
const filetype = req.query.filetype
const currentUser = req.currentUser;
const payload = await RolesDBApi.findAll(
req.query, { currentUser }
);
if (filetype && filetype === 'csv') {
const fields = ['id','name',
];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment(csv);
res.send(csv)
} catch (err) {
console.error(err);
}
} else {
res.status(200).send(payload);
}
}));
/**
* @swagger
* /api/roles/count:
* get:
* security:
* - bearerAuth: []
* tags: [Roles]
* summary: Count all roles
* description: Count all roles
* responses:
* 200:
* description: Roles count successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Roles"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/count', wrapAsync(async (req, res) => {
const currentUser = req.currentUser;
const payload = await RolesDBApi.findAll(
req.query,
null,
{ countOnly: true, currentUser }
);
res.status(200).send(payload);
}));
/**
* @swagger
* /api/roles/autocomplete:
* get:
* security:
* - bearerAuth: []
* tags: [Roles]
* summary: Find all roles that match search criteria
* description: Find all roles that match search criteria
* responses:
* 200:
* description: Roles list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Roles"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/autocomplete', async (req, res) => {
const payload = await RolesDBApi.findAllAutocomplete(
req.query.query,
req.query.limit,
req.query.offset,
);
res.status(200).send(payload);
});
/**
* @swagger
* /api/roles/{id}:
* put:
* security:
* - bearerAuth: []
* tags: [Roles]
* summary: Update the data of the selected item
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: string
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* id:
* type: string
* data:
* type: object
* $ref: "#/components/schemas/Roles"
* responses:
* 200:
* description: The item data was successfully updated
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
* delete:
* security:
* - bearerAuth: []
* tags: [Roles]
* summary: Delete the selected item
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: string
* responses:
* 200:
* description: The item was successfully deleted
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
* get:
* security:
* - bearerAuth: []
* tags: [Roles]
* summary: Get selected item
* description: Get selected item
* parameters:
* - in: path
* name: id
* description: ID of item to get
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Selected item successfully received
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Roles"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
@ -414,16 +137,5 @@ router.get('/autocomplete', async (req, res) => {
* 500:
* description: Some server error
*/
router.get('/:id', wrapAsync(async (req, res) => {
const payload = await RolesDBApi.findBy(
{ id: req.params.id },
);
res.status(200).send(payload);
}));
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;
module.exports = createEntityRouter('roles', RolesService, RolesDBApi);

View File

@ -1,22 +1,6 @@
const express = require('express');
const Tour_pagesService = require('../services/tour_pages');
const Tour_pagesDBApi = require('../db/api/tour_pages');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const { parse } = require('json2csv');
const {
checkCrudPermissions,
} = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('tour_pages'));
const { createEntityRouter } = require('../factories/router.factory');
/**
* @swagger
@ -25,35 +9,22 @@ router.use(checkCrudPermissions('tour_pages'));
* Tour_pages:
* type: object
* properties:
* source_key:
* type: string
* default: source_key
* name:
* type: string
* default: name
* slug:
* type: string
* default: slug
* background_image_url:
* type: string
* default: background_image_url
* background_video_url:
* type: string
* default: background_video_url
* background_audio_url:
* type: string
* default: background_audio_url
* ui_schema_json:
* type: string
* default: ui_schema_json
* sort_order:
* type: integer
* format: int64
*
*/
/**
@ -71,7 +42,6 @@ router.use(checkCrudPermissions('tour_pages'));
* - bearerAuth: []
* tags: [Tour_pages]
* summary: Add new item
* description: Add new item
* requestBody:
* required: true
* content:
@ -79,73 +49,28 @@ router.use(checkCrudPermissions('tour_pages'));
* schema:
* properties:
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Tour_pages"
* responses:
* 200:
* description: The item was successfully added
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Tour_pages"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*/
router.post('/', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Tour_pagesService.create(req.body.data, req.currentUser, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/budgets/bulk-import:
* post:
* get:
* security:
* - bearerAuth: []
* tags: [Tour_pages]
* summary: Bulk import items
* description: Bulk import items
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated items
* type: array
* items:
* $ref: "#/components/schemas/Tour_pages"
* summary: Get all tour_pages
* responses:
* 200:
* description: The items were successfully imported
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Tour_pages"
* description: Tour_pages list successfully received
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*
*/
router.post('/bulk-import', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await Tour_pagesService.bulkImport(req, res, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
@ -154,283 +79,67 @@ router.post('/bulk-import', wrapAsync(async (req, res) => {
* security:
* - bearerAuth: []
* tags: [Tour_pages]
* summary: Update the data of the selected item
* description: Update the data of the selected item
* summary: Update the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to update
* required: true
* schema:
* type: string
* requestBody:
* description: Set new item data
* required: true
* content:
* application/json:
* schema:
* properties:
* id:
* description: ID of the updated item
* type: string
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Tour_pages"
* required:
* - id
* responses:
* 200:
* description: The item data was successfully updated
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Tour_pages"
* 400:
* description: Invalid ID supplied
* description: The item was successfully updated
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.put('/:id', wrapAsync(async (req, res) => {
await Tour_pagesService.update(req.body.data, req.body.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/tour_pages/{id}:
* delete:
* security:
* - bearerAuth: []
* tags: [Tour_pages]
* summary: Delete the selected item
* description: Delete the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to delete
* required: true
* schema:
* type: string
* responses:
* 200:
* description: The item was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Tour_pages"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.delete('/:id', wrapAsync(async (req, res) => {
await Tour_pagesService.remove(req.params.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/tour_pages/deleteByIds:
* post:
* security:
* - bearerAuth: []
* tags: [Tour_pages]
* summary: Delete the selected item list
* description: Delete the selected item list
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* ids:
* description: IDs of the updated items
* type: array
* responses:
* 200:
* description: The items was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Tour_pages"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Items not found
* 500:
* description: Some server error
*/
router.post('/deleteByIds', wrapAsync(async (req, res) => {
await Tour_pagesService.deleteByIds(req.body.data, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/tour_pages:
* get:
* security:
* - bearerAuth: []
* tags: [Tour_pages]
* summary: Get all tour_pages
* description: Get all tour_pages
* responses:
* 200:
* description: Tour_pages list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Tour_pages"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/', wrapAsync(async (req, res) => {
const filetype = req.query.filetype
const currentUser = req.currentUser;
const runtimeContext = req.runtimeContext;
const payload = await Tour_pagesDBApi.findAll(
req.query, { currentUser, runtimeContext }
);
if (filetype && filetype === 'csv') {
const fields = ['id','source_key','name','slug','background_image_url','background_video_url','background_audio_url','ui_schema_json',
'sort_order',
];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment(csv);
res.send(csv)
} catch (err) {
console.error(err);
}
} else {
res.status(200).send(payload);
}
}));
/**
* @swagger
* /api/tour_pages/count:
* get:
* security:
* - bearerAuth: []
* tags: [Tour_pages]
* summary: Count all tour_pages
* description: Count all tour_pages
* responses:
* 200:
* description: Tour_pages count successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Tour_pages"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/count', wrapAsync(async (req, res) => {
const currentUser = req.currentUser;
const runtimeContext = req.runtimeContext;
const payload = await Tour_pagesDBApi.findAll(
req.query,
null,
{ countOnly: true, currentUser, runtimeContext }
);
res.status(200).send(payload);
}));
/**
* @swagger
* /api/tour_pages/autocomplete:
* get:
* security:
* - bearerAuth: []
* tags: [Tour_pages]
* summary: Find all tour_pages that match search criteria
* description: Find all tour_pages that match search criteria
* responses:
* 200:
* description: Tour_pages list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Tour_pages"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/autocomplete', async (req, res) => {
const payload = await Tour_pagesDBApi.findAllAutocomplete(
req.query.query,
req.query.limit,
req.query.offset,
);
res.status(200).send(payload);
});
/**
* @swagger
* /api/tour_pages/{id}:
* get:
* security:
* - bearerAuth: []
* tags: [Tour_pages]
* summary: Get selected item
* description: Get selected item
* parameters:
* - in: path
* name: id
* description: ID of item to get
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Selected item successfully received
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Tour_pages"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
@ -438,18 +147,5 @@ router.get('/autocomplete', async (req, res) => {
* 500:
* description: Some server error
*/
router.get('/:id', wrapAsync(async (req, res) => {
const runtimeContext = req.runtimeContext;
const payload = await Tour_pagesDBApi.findBy(
{ id: req.params.id },
{ runtimeContext },
);
res.status(200).send(payload);
}));
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;
module.exports = createEntityRouter('tour_pages', Tour_pagesService, Tour_pagesDBApi);

View File

@ -1,22 +1,6 @@
const express = require('express');
const TransitionsService = require('../services/transitions');
const TransitionsDBApi = require('../db/api/transitions');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const { parse } = require('json2csv');
const {
checkCrudPermissions,
} = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('transitions'));
const { createEntityRouter } = require('../factories/router.factory');
/**
* @swagger
@ -25,29 +9,18 @@ router.use(checkCrudPermissions('transitions'));
* Transitions:
* type: object
* properties:
* source_key:
* type: string
* default: source_key
* name:
* type: string
* default: name
* slug:
* type: string
* default: slug
* video_url:
* type: string
* default: video_url
* audio_url:
* type: string
* default: audio_url
* duration_sec:
* type: integer
* format: int64
*
* type: number
*/
/**
@ -65,7 +38,6 @@ router.use(checkCrudPermissions('transitions'));
* - bearerAuth: []
* tags: [Transitions]
* summary: Add new item
* description: Add new item
* requestBody:
* required: true
* content:
@ -73,73 +45,28 @@ router.use(checkCrudPermissions('transitions'));
* schema:
* properties:
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Transitions"
* responses:
* 200:
* description: The item was successfully added
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Transitions"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*/
router.post('/', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await TransitionsService.create(req.body.data, req.currentUser, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/budgets/bulk-import:
* post:
* get:
* security:
* - bearerAuth: []
* tags: [Transitions]
* summary: Bulk import items
* description: Bulk import items
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* data:
* description: Data of the updated items
* type: array
* items:
* $ref: "#/components/schemas/Transitions"
* summary: Get all transitions
* responses:
* 200:
* description: The items were successfully imported
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Transitions"
* description: Transitions list successfully received
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 405:
* description: Invalid input data
* 500:
* description: Some server error
*
*/
router.post('/bulk-import', wrapAsync(async (req, res) => {
const referer = req.headers.referer || `${req.protocol}://${req.hostname}${req.originalUrl}`;
const link = new URL(referer);
await TransitionsService.bulkImport(req, res, true, link.host);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
@ -148,283 +75,67 @@ router.post('/bulk-import', wrapAsync(async (req, res) => {
* security:
* - bearerAuth: []
* tags: [Transitions]
* summary: Update the data of the selected item
* description: Update the data of the selected item
* summary: Update the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to update
* required: true
* schema:
* type: string
* requestBody:
* description: Set new item data
* required: true
* content:
* application/json:
* schema:
* properties:
* id:
* description: ID of the updated item
* type: string
* data:
* description: Data of the updated item
* type: object
* $ref: "#/components/schemas/Transitions"
* required:
* - id
* responses:
* 200:
* description: The item data was successfully updated
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Transitions"
* 400:
* description: Invalid ID supplied
* description: The item was successfully updated
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.put('/:id', wrapAsync(async (req, res) => {
await TransitionsService.update(req.body.data, req.body.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/transitions/{id}:
* delete:
* security:
* - bearerAuth: []
* tags: [Transitions]
* summary: Delete the selected item
* description: Delete the selected item
* parameters:
* - in: path
* name: id
* description: Item ID to delete
* required: true
* schema:
* type: string
* responses:
* 200:
* description: The item was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Transitions"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Item not found
* 500:
* description: Some server error
*/
router.delete('/:id', wrapAsync(async (req, res) => {
await TransitionsService.remove(req.params.id, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/transitions/deleteByIds:
* post:
* security:
* - bearerAuth: []
* tags: [Transitions]
* summary: Delete the selected item list
* description: Delete the selected item list
* requestBody:
* required: true
* content:
* application/json:
* schema:
* properties:
* ids:
* description: IDs of the updated items
* type: array
* responses:
* 200:
* description: The items was successfully deleted
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Transitions"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Items not found
* 500:
* description: Some server error
*/
router.post('/deleteByIds', wrapAsync(async (req, res) => {
await TransitionsService.deleteByIds(req.body.data, req.currentUser);
const payload = true;
res.status(200).send(payload);
}));
/**
* @swagger
* /api/transitions:
* get:
* security:
* - bearerAuth: []
* tags: [Transitions]
* summary: Get all transitions
* description: Get all transitions
* responses:
* 200:
* description: Transitions list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Transitions"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/', wrapAsync(async (req, res) => {
const filetype = req.query.filetype
const currentUser = req.currentUser;
const runtimeContext = req.runtimeContext;
const payload = await TransitionsDBApi.findAll(
req.query, { currentUser, runtimeContext }
);
if (filetype && filetype === 'csv') {
const fields = ['id','source_key','name','slug','video_url','audio_url',
'duration_sec',
];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment(csv);
res.send(csv)
} catch (err) {
console.error(err);
}
} else {
res.status(200).send(payload);
}
}));
/**
* @swagger
* /api/transitions/count:
* get:
* security:
* - bearerAuth: []
* tags: [Transitions]
* summary: Count all transitions
* description: Count all transitions
* responses:
* 200:
* description: Transitions count successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Transitions"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/count', wrapAsync(async (req, res) => {
const currentUser = req.currentUser;
const runtimeContext = req.runtimeContext;
const payload = await TransitionsDBApi.findAll(
req.query,
null,
{ countOnly: true, currentUser, runtimeContext }
);
res.status(200).send(payload);
}));
/**
* @swagger
* /api/transitions/autocomplete:
* get:
* security:
* - bearerAuth: []
* tags: [Transitions]
* summary: Find all transitions that match search criteria
* description: Find all transitions that match search criteria
* responses:
* 200:
* description: Transitions list successfully received
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: "#/components/schemas/Transitions"
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
* description: Data not found
* 500:
* description: Some server error
*/
router.get('/autocomplete', async (req, res) => {
const payload = await TransitionsDBApi.findAllAutocomplete(
req.query.query,
req.query.limit,
req.query.offset,
);
res.status(200).send(payload);
});
/**
* @swagger
* /api/transitions/{id}:
* get:
* security:
* - bearerAuth: []
* tags: [Transitions]
* summary: Get selected item
* description: Get selected item
* parameters:
* - in: path
* name: id
* description: ID of item to get
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Selected item successfully received
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/Transitions"
* 400:
* description: Invalid ID supplied
* 401:
* $ref: "#/components/responses/UnauthorizedError"
* 404:
@ -432,18 +143,5 @@ router.get('/autocomplete', async (req, res) => {
* 500:
* description: Some server error
*/
router.get('/:id', wrapAsync(async (req, res) => {
const runtimeContext = req.runtimeContext;
const payload = await TransitionsDBApi.findBy(
{ id: req.params.id },
{ runtimeContext },
);
res.status(200).send(payload);
}));
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;
module.exports = createEntityRouter('transitions', TransitionsService, TransitionsDBApi);

View File

@ -1,103 +0,0 @@
const express = require('express');
const Ui_elementsService = require('../services/ui_elements');
const Ui_elementsDBApi = require('../db/api/ui_elements');
const wrapAsync = require('../helpers').wrapAsync;
const router = express.Router();
const { parse } = require('json2csv');
const { checkCrudPermissions } = require('../middlewares/check-permissions');
router.use(checkCrudPermissions('page_elements'));
router.post(
'/',
wrapAsync(async (req, res) => {
await Ui_elementsService.create(req.body.data, req.currentUser);
res.status(200).send(true);
}),
);
router.post(
'/bulk-import',
wrapAsync(async (req, res) => {
await Ui_elementsService.bulkImport(req, res);
res.status(200).send(true);
}),
);
router.put(
'/:id',
wrapAsync(async (req, res) => {
await Ui_elementsService.update(req.body.data, req.body.id, req.currentUser);
res.status(200).send(true);
}),
);
router.delete(
'/:id',
wrapAsync(async (req, res) => {
await Ui_elementsService.remove(req.params.id, req.currentUser);
res.status(200).send(true);
}),
);
router.post(
'/deleteByIds',
wrapAsync(async (req, res) => {
await Ui_elementsService.deleteByIds(req.body.data, req.currentUser);
res.status(200).send(true);
}),
);
router.get(
'/',
wrapAsync(async (req, res) => {
const filetype = req.query.filetype;
const payload = await Ui_elementsDBApi.findAll(req.query, {
currentUser: req.currentUser,
});
if (filetype && filetype === 'csv') {
const fields = ['id', 'name', 'element_type', 'settings_json', 'sort_order'];
const opts = { fields };
try {
const csv = parse(payload.rows, opts);
res.status(200).attachment(csv);
res.send(csv);
} catch (err) {
console.error(err);
throw err;
}
} else {
res.status(200).send(payload);
}
}),
);
router.get(
'/count',
wrapAsync(async (req, res) => {
const payload = await Ui_elementsDBApi.findAll(req.query, { countOnly: true, currentUser: req.currentUser });
res.status(200).send(payload);
}),
);
router.get('/autocomplete', async (req, res) => {
const payload = await Ui_elementsDBApi.findAllAutocomplete(req.query.query, req.query.limit, req.query.offset);
res.status(200).send(payload);
});
router.get(
'/:id',
wrapAsync(async (req, res) => {
const payload = await Ui_elementsDBApi.findBy({ id: req.params.id });
res.status(200).send(payload);
}),
);
router.use('/', require('../helpers').commonErrorHandler);
module.exports = router;

View File

@ -120,6 +120,7 @@ module.exports = class ProjectsService {
{
name: sourceAsset.name,
asset_type: sourceAsset.asset_type,
type: sourceAsset.type || 'general',
cdn_url: sourceAsset.cdn_url,
storage_key: sourceAsset.storage_key,
mime_type: sourceAsset.mime_type,

View File

@ -1,114 +0,0 @@
const db = require('../db/models');
const Ui_elementsDBApi = require('../db/api/ui_elements');
const processFile = require('../middlewares/upload');
const ValidationError = require('./notifications/errors/validation');
const csv = require('csv-parser');
const stream = require('stream');
module.exports = class Ui_elementsService {
static async create(data, currentUser) {
const transaction = await db.sequelize.transaction();
try {
await Ui_elementsDBApi.create(data, {
currentUser,
transaction,
});
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
}
static async bulkImport(req, res) {
const transaction = await db.sequelize.transaction();
try {
await processFile(req, res);
const bufferStream = new stream.PassThrough();
const results = [];
await bufferStream.end(Buffer.from(req.file.buffer, 'utf-8'));
await new Promise((resolve, reject) => {
bufferStream
.pipe(csv())
.on('data', (data) => results.push(data))
.on('end', async () => {
resolve();
})
.on('error', (error) => reject(error));
});
await Ui_elementsDBApi.bulkImport(results, {
transaction,
ignoreDuplicates: true,
validate: true,
currentUser: req.currentUser,
});
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
}
static async update(data, id, currentUser) {
const transaction = await db.sequelize.transaction();
try {
const ui_elements = await Ui_elementsDBApi.findBy(
{ id },
{ transaction },
);
if (!ui_elements) {
throw new ValidationError('ui_elementsNotFound');
}
const updatedUiElements = await Ui_elementsDBApi.update(id, data, {
currentUser,
transaction,
});
await transaction.commit();
return updatedUiElements;
} catch (error) {
await transaction.rollback();
throw error;
}
}
static async deleteByIds(ids, currentUser) {
const transaction = await db.sequelize.transaction();
try {
await Ui_elementsDBApi.deleteByIds(ids, {
currentUser,
transaction,
});
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
}
static async remove(id, currentUser) {
const transaction = await db.sequelize.transaction();
try {
await Ui_elementsDBApi.remove(id, {
currentUser,
transaction,
});
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
}
};

View File

@ -0,0 +1,79 @@
const { logger } = require('./logger');
class CircuitBreaker {
constructor(options = {}) {
this.name = options.name || 'default';
this.failureThreshold = options.failureThreshold || 5;
this.resetTimeout = options.resetTimeout || 30000;
this.failures = 0;
this.state = 'CLOSED';
this.nextAttempt = Date.now();
}
async execute(fn) {
if (this.state === 'OPEN') {
if (Date.now() < this.nextAttempt) {
logger.warn({ circuitBreaker: this.name, state: this.state }, 'Circuit breaker is OPEN, rejecting request');
throw new Error(`Circuit breaker ${this.name} is OPEN`);
}
this.state = 'HALF-OPEN';
logger.info({ circuitBreaker: this.name }, 'Circuit breaker moved to HALF-OPEN');
}
try {
const result = await fn();
this.onSuccess();
return result;
} catch (error) {
this.onFailure(error);
throw error;
}
}
onSuccess() {
if (this.state === 'HALF-OPEN') {
logger.info({ circuitBreaker: this.name }, 'Circuit breaker recovered, moving to CLOSED');
}
this.failures = 0;
this.state = 'CLOSED';
}
onFailure(error) {
this.failures++;
logger.warn({
circuitBreaker: this.name,
failures: this.failures,
threshold: this.failureThreshold,
error: error.message,
}, 'Circuit breaker recorded failure');
if (this.failures >= this.failureThreshold) {
this.state = 'OPEN';
this.nextAttempt = Date.now() + this.resetTimeout;
logger.error({
circuitBreaker: this.name,
resetAt: new Date(this.nextAttempt).toISOString(),
}, 'Circuit breaker tripped to OPEN');
}
}
getState() {
return {
name: this.name,
state: this.state,
failures: this.failures,
nextAttempt: this.state === 'OPEN' ? new Date(this.nextAttempt).toISOString() : null,
};
}
}
const circuitBreakers = new Map();
function getCircuitBreaker(name, options = {}) {
if (!circuitBreakers.has(name)) {
circuitBreakers.set(name, new CircuitBreaker({ name, ...options }));
}
return circuitBreakers.get(name);
}
module.exports = { CircuitBreaker, getCircuitBreaker };

View File

@ -0,0 +1,65 @@
const Joi = require('joi');
const envSchema = Joi.object({
NODE_ENV: Joi.string()
.valid('development', 'test', 'production', 'dev_stage')
.default('development'),
PORT: Joi.number().default(8080),
DB_HOST: Joi.string().default('localhost'),
DB_PORT: Joi.number().default(5432),
DB_NAME: Joi.string().default('db_tour_builder_platform'),
DB_USER: Joi.string().default('postgres'),
DB_PASS: Joi.string().allow('').default(''),
SECRET_KEY: Joi.string().min(16).default('88dbeaf8-e906-405e-9e41-c3baadeda5c6'),
ADMIN_PASS: Joi.string().default('88dbeaf8'),
USER_PASS: Joi.string().default('c3baadeda5c6'),
ADMIN_EMAIL: Joi.string().email().default('admin@flatlogic.com'),
GOOGLE_CLIENT_ID: Joi.string().allow('').default(''),
GOOGLE_CLIENT_SECRET: Joi.string().allow('').default(''),
MS_CLIENT_ID: Joi.string().allow('').default(''),
MS_CLIENT_SECRET: Joi.string().allow('').default(''),
AWS_ACCESS_KEY_ID: Joi.string().allow('').default(''),
AWS_SECRET_ACCESS_KEY: Joi.string().allow('').default(''),
AWS_S3_BUCKET: Joi.string().allow('').default(''),
AWS_S3_REGION: Joi.string().default('us-east-1'),
AWS_S3_PREFIX: Joi.string().default('afeefb9d49f5b7977577876b99532ac7'),
EMAIL_USER: Joi.string().allow('').default(''),
EMAIL_PASS: Joi.string().allow('').default(''),
EMAIL_TLS_REJECT_UNAUTHORIZED: Joi.string().valid('true', 'false').default('true'),
GPT_KEY: Joi.string().allow('').default(''),
PEXELS_KEY: Joi.string().allow('').default(''),
LOG_LEVEL: Joi.string()
.valid('fatal', 'error', 'warn', 'info', 'debug', 'trace')
.default('info'),
}).unknown(true);
function validateEnv() {
const { error, value } = envSchema.validate(process.env, {
abortEarly: false,
stripUnknown: false,
});
if (error) {
const messages = error.details.map(d => ` - ${d.message}`).join('\n');
console.error('Environment validation failed:\n' + messages);
if (process.env.NODE_ENV === 'production') {
process.exit(1);
} else {
console.warn('Continuing with default values in non-production mode');
}
}
return value;
}
module.exports = { validateEnv, envSchema };

View File

@ -0,0 +1,48 @@
class AppError extends Error {
constructor(message, statusCode = 500, details = null) {
super(message);
this.statusCode = statusCode;
this.details = details;
this.isOperational = true;
Error.captureStackTrace(this, this.constructor);
}
}
class NotFoundError extends AppError {
constructor(resource = 'Resource') {
super(`${resource} not found`, 404);
}
}
class ValidationError extends AppError {
constructor(message, details = null) {
super(message, 400, details);
}
}
class ForbiddenError extends AppError {
constructor(message = 'Access denied') {
super(message, 403);
}
}
class UnauthorizedError extends AppError {
constructor(message = 'Unauthorized') {
super(message, 401);
}
}
class ConflictError extends AppError {
constructor(message = 'Resource conflict') {
super(message, 409);
}
}
module.exports = {
AppError,
NotFoundError,
ValidationError,
ForbiddenError,
UnauthorizedError,
ConflictError,
};

View File

@ -0,0 +1,53 @@
const EventEmitter = require('events');
const { logger } = require('./logger');
class AppEventEmitter extends EventEmitter {
emit(event, data) {
logger.debug({ event, hasListeners: this.listenerCount(event) > 0 }, 'Event emitted');
return super.emit(event, data);
}
async emitAsync(event, data) {
logger.debug({ event, listenerCount: this.listenerCount(event) }, 'Async event emitted');
const results = await Promise.allSettled(
this.listeners(event).map(listener => listener(data))
);
const failures = results.filter(r => r.status === 'rejected');
if (failures.length > 0) {
logger.warn({ event, failures: failures.map(f => f.reason?.message) }, 'Some event listeners failed');
}
return results;
}
onAsync(event, listener) {
this.on(event, async (data) => {
try {
await listener(data);
} catch (error) {
logger.error({ event, error: error.message }, 'Async event listener error');
}
});
}
}
const appEvents = new AppEventEmitter();
appEvents.on('user.created', (user) => {
logger.info({ userId: user.id, email: user.email }, 'User created event received');
});
appEvents.on('project.created', (project) => {
logger.info({ projectId: project.id, name: project.name }, 'Project created event received');
});
appEvents.on('project.published', (project) => {
logger.info({ projectId: project.id, slug: project.slug }, 'Project published event received');
});
appEvents.on('error', (error) => {
logger.error({ error: error.message }, 'Application event error');
});
module.exports = { appEvents, AppEventEmitter };

View File

@ -0,0 +1,7 @@
module.exports = {
...require('./errors'),
...require('./logger'),
...require('./circuit-breaker'),
...require('./events'),
envValidation: require('./env-validation'),
};

View File

@ -0,0 +1,46 @@
const pino = require('pino');
const crypto = require('crypto');
const isDevelopment = process.env.NODE_ENV === 'development';
const logger = pino({
level: process.env.LOG_LEVEL || 'info',
transport: isDevelopment
? { target: 'pino-pretty', options: { colorize: true } }
: undefined,
base: {
service: 'tour-builder-api',
env: process.env.NODE_ENV || 'development',
},
});
function requestLogger(req, res, next) {
const requestId = req.headers['x-request-id'] || crypto.randomUUID();
req.log = logger.child({ requestId });
req.requestId = requestId;
res.setHeader('X-Request-Id', requestId);
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
const logData = {
method: req.method,
url: req.originalUrl || req.url,
status: res.statusCode,
duration,
userAgent: req.headers['user-agent'],
};
if (res.statusCode >= 500) {
req.log.error(logData, 'Request completed with server error');
} else if (res.statusCode >= 400) {
req.log.warn(logData, 'Request completed with client error');
} else {
req.log.info(logData, 'Request completed');
}
});
next();
}
module.exports = { logger, requestLogger };

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
{}

View File

@ -12,11 +12,11 @@
"@emotion/styled": "^11.11.0",
"@mdi/js": "^7.4.47",
"@mui/material": "^6.3.0",
"@mui/x-data-grid": "^6.19.2",
"@mui/x-data-grid": "^7.0.0",
"@reduxjs/toolkit": "^2.1.0",
"@tailwindcss/typography": "^0.5.13",
"@tinymce/tinymce-react": "^4.3.2",
"apexcharts": "^3.45.2",
"apexcharts": "^5.0.0",
"axios": "^1.8.4",
"chart.js": "^4.4.1",
"chroma-js": "^2.4.2",
@ -30,7 +30,7 @@
"intro.js": "^7.2.0",
"intro.js-react": "^1.0.0",
"jsonwebtoken": "^9.0.2",
"jwt-decode": "^3.1.2",
"jwt-decode": "^4.0.0",
"lodash": "^4.17.21",
"moment": "^2.30.1",
"next": "^15.3.1",
@ -38,21 +38,22 @@
"numeral": "^2.0.6",
"query-string": "^8.1.0",
"react": "^19.0.0",
"react-apexcharts": "^1.4.1",
"react-big-calendar": "^1.10.3",
"react-chartjs-2": "^4.3.1",
"react-datepicker": "^4.10.0",
"react-apexcharts": "^2.0.0",
"react-big-calendar": "^1.19.0",
"react-chartjs-2": "^5.0.0",
"react-datepicker": "^7.0.0",
"react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1",
"react-dom": "^19.0.0",
"react-i18next": "^15.5.1",
"react-redux": "^8.0.2",
"react-redux": "^9.0.0",
"react-select": "^5.7.0",
"react-select-async-paginate": "^0.7.9",
"react-switch": "^7.0.0",
"react-toastify": "^11.0.2",
"swr": "^1.3.0",
"uuid": "^9.0.0"
"swr": "^2.0.0",
"uuid": "^9.0.0",
"zod": "^4.3.6"
},
"devDependencies": {
"@tailwindcss/forms": "^0.5.7",

View File

@ -0,0 +1,99 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Offline - Tour Builder</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
background-color: #1f2937;
color: #ffffff;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 2rem;
text-align: center;
}
.container {
max-width: 400px;
}
.icon {
width: 80px;
height: 80px;
margin-bottom: 2rem;
opacity: 0.6;
}
h1 {
font-size: 1.5rem;
margin-bottom: 1rem;
font-weight: 600;
}
p {
color: #9ca3af;
margin-bottom: 2rem;
line-height: 1.6;
}
.retry-btn {
display: inline-block;
padding: 0.75rem 1.5rem;
background-color: #3b82f6;
color: #ffffff;
border: none;
border-radius: 0.5rem;
font-size: 1rem;
font-weight: 500;
cursor: pointer;
transition: background-color 0.2s;
}
.retry-btn:hover {
background-color: #2563eb;
}
.retry-btn:active {
background-color: #1d4ed8;
}
</style>
</head>
<body>
<div class="container">
<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M18.364 5.636a9 9 0 010 12.728M5.636 18.364a9 9 0 010-12.728" />
<path d="M15.536 8.464a5 5 0 010 7.072M8.464 15.536a5 5 0 010-7.072" />
<circle cx="12" cy="12" r="1" fill="currentColor" />
</svg>
<h1>You're Offline</h1>
<p>
It looks like you've lost your internet connection.
Some features may not be available until you're back online.
</p>
<button class="retry-btn" onclick="window.location.reload()">
Try Again
</button>
</div>
<script>
// Auto-retry when connection is restored
window.addEventListener('online', () => {
window.location.reload();
});
</script>
</body>
</html>

210
frontend/public/sw.js Normal file
View File

@ -0,0 +1,210 @@
/**
* Tour Builder Platform - Service Worker
*
* Provides offline caching for PWA functionality.
* Caches tour assets (images, videos, audio) for offline viewing.
*/
const CACHE_NAME = 'tour-builder-v1';
const STATIC_CACHE_NAME = 'tour-builder-static-v1';
const DYNAMIC_CACHE_NAME = 'tour-builder-dynamic-v1';
// Static assets to cache on install
const STATIC_ASSETS = [
'/',
'/runtime',
'/offline.html',
];
// Asset types to cache
const CACHEABLE_EXTENSIONS = [
'.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg', '.ico',
'.mp4', '.webm', '.mov',
'.mp3', '.wav', '.ogg', '.m4a',
'.woff', '.woff2', '.ttf', '.eot',
'.css', '.js',
];
// Check if request should be cached
const isCacheableRequest = (request) => {
const url = new URL(request.url);
// Don't cache API requests (except static assets from /file/download)
if (url.pathname.startsWith('/api/') && !url.pathname.includes('/file/download')) {
return false;
}
// Cache known asset extensions
const hasExtension = CACHEABLE_EXTENSIONS.some((ext) => url.pathname.toLowerCase().endsWith(ext));
if (hasExtension) {
return true;
}
// Cache file downloads (S3 presigned URLs, CDN assets)
if (url.pathname.includes('/file/download') || url.hostname.includes('amazonaws.com') || url.hostname.includes('cloudfront.net')) {
return true;
}
return false;
};
// Install event - cache static assets
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(STATIC_CACHE_NAME).then((cache) => {
console.log('[SW] Caching static assets');
return cache.addAll(STATIC_ASSETS).catch((error) => {
console.warn('[SW] Failed to cache some static assets:', error);
});
})
);
self.skipWaiting();
});
// Activate event - clean up old caches
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames
.filter((name) => {
return name.startsWith('tour-builder-') && name !== STATIC_CACHE_NAME && name !== DYNAMIC_CACHE_NAME;
})
.map((name) => {
console.log('[SW] Deleting old cache:', name);
return caches.delete(name);
})
);
})
);
self.clients.claim();
});
// Fetch event - serve from cache or network
self.addEventListener('fetch', (event) => {
const { request } = event;
// Only handle GET requests
if (request.method !== 'GET') {
return;
}
// Skip non-http(s) requests
if (!request.url.startsWith('http')) {
return;
}
event.respondWith(
caches.match(request).then((cachedResponse) => {
// Return cached response if available
if (cachedResponse) {
// Optionally update cache in background (stale-while-revalidate)
if (isCacheableRequest(request)) {
event.waitUntil(
fetch(request)
.then((networkResponse) => {
if (networkResponse && networkResponse.status === 200) {
const responseToCache = networkResponse.clone();
caches.open(DYNAMIC_CACHE_NAME).then((cache) => {
cache.put(request, responseToCache);
});
}
})
.catch(() => {
// Network failed, but we have cache - that's fine
})
);
}
return cachedResponse;
}
// Fetch from network
return fetch(request)
.then((networkResponse) => {
// Cache successful responses for cacheable requests
if (networkResponse && networkResponse.status === 200 && isCacheableRequest(request)) {
const responseToCache = networkResponse.clone();
caches.open(DYNAMIC_CACHE_NAME).then((cache) => {
cache.put(request, responseToCache);
});
}
return networkResponse;
})
.catch((error) => {
console.warn('[SW] Fetch failed:', error);
// Return offline page for navigation requests
if (request.mode === 'navigate') {
return caches.match('/offline.html');
}
// Return empty response for assets
return new Response('', {
status: 503,
statusText: 'Service Unavailable',
});
});
})
);
});
// Message event - handle commands from main thread
self.addEventListener('message', (event) => {
const { type, payload } = event.data || {};
switch (type) {
case 'CACHE_ASSETS':
// Cache specific assets for a project/page
if (Array.isArray(payload?.urls)) {
event.waitUntil(
caches.open(DYNAMIC_CACHE_NAME).then((cache) => {
return Promise.all(
payload.urls.map((url) =>
fetch(url)
.then((response) => {
if (response.status === 200) {
return cache.put(url, response);
}
})
.catch((error) => {
console.warn('[SW] Failed to cache asset:', url, error);
})
)
);
})
);
}
break;
case 'CLEAR_CACHE':
// Clear all dynamic caches
event.waitUntil(
caches.delete(DYNAMIC_CACHE_NAME).then(() => {
console.log('[SW] Dynamic cache cleared');
})
);
break;
case 'GET_CACHE_STATUS':
// Return current cache status
event.waitUntil(
caches.open(DYNAMIC_CACHE_NAME).then((cache) => {
return cache.keys().then((keys) => {
event.source.postMessage({
type: 'CACHE_STATUS',
payload: {
cachedCount: keys.length,
urls: keys.map((request) => request.url),
},
});
});
})
);
break;
default:
break;
}
});
console.log('[SW] Service worker loaded');

View File

@ -1,21 +1,22 @@
import type { ColorButtonKey } from './interfaces'
import type { ColorButtonKey } from './interfaces';
export const gradientBgBase = 'bg-gradient-to-tr'
export const colorBgBase = "bg-violet-50/50"
export const gradientBgPurplePink = `${gradientBgBase} from-purple-400 via-pink-500 to-red-500`
export const gradientBgViolet = `${gradientBgBase} ${colorBgBase}`
export const gradientBgBase = 'bg-gradient-to-tr';
export const colorBgBase = 'bg-violet-50/50';
export const gradientBgPurplePink = `${gradientBgBase} from-purple-400 via-pink-500 to-red-500`;
export const gradientBgViolet = `${gradientBgBase} ${colorBgBase}`;
export const gradientBgDark = `${gradientBgBase} from-dark-700 via-dark-900 to-dark-800`;
export const gradientBgPinkRed = `${gradientBgBase} from-pink-400 via-red-500 to-yellow-500`
export const gradientBgPinkRed = `${gradientBgBase} from-pink-400 via-red-500 to-yellow-500`;
export const colorsBgLight = {
white: 'bg-white text-black',
light: ' bg-white text-black text-black dark:bg-dark-900 dark:text-white',
contrast: 'bg-gray-800 text-white dark:bg-white dark:text-black',
success: 'bg-emerald-500 border-emerald-500 dark:bg-pavitra-blue dark:border-pavitra-blue text-white',
success:
'bg-emerald-500 border-emerald-500 dark:bg-pavitra-blue dark:border-pavitra-blue text-white',
danger: 'bg-red-500 border-red-500 text-white',
warning: 'bg-yellow-500 border-yellow-500 text-white',
info: 'bg-blue-500 border-blue-500 dark:bg-pavitra-blue dark:border-pavitra-blue text-white',
}
};
export const colorsText = {
white: 'text-black dark:text-slate-100',
@ -30,7 +31,9 @@ export const colorsText = {
export const colorsOutline = {
white: [colorsText.white, 'border-gray-100'].join(' '),
light: [colorsText.light, 'border-gray-100'].join(' '),
contrast: [colorsText.contrast, 'border-gray-900 dark:border-slate-100'].join(' '),
contrast: [colorsText.contrast, 'border-gray-900 dark:border-slate-100'].join(
' ',
),
success: [colorsText.success, 'border-emerald-500'].join(' '),
danger: [colorsText.danger, 'border-red-500'].join(' '),
warning: [colorsText.warning, 'border-yellow-500'].join(' '),
@ -41,10 +44,10 @@ export const getButtonColor = (
color: ColorButtonKey,
isOutlined: boolean,
hasHover: boolean,
isActive = false
isActive = false,
) => {
if (color === 'void') {
return ''
return '';
}
const colors = {
@ -56,7 +59,7 @@ export const getButtonColor = (
success: 'ring-emerald-300 dark:ring-pavitra-blue',
danger: 'ring-red-300 dark:ring-red-700',
warning: 'ring-yellow-300 dark:ring-yellow-700',
info: "ring-blue-300 dark:ring-pavitra-blue",
info: 'ring-blue-300 dark:ring-pavitra-blue',
},
active: {
white: 'bg-gray-100',
@ -76,7 +79,7 @@ export const getButtonColor = (
success: 'bg-emerald-600 dark:bg-pavitra-blue text-white',
danger: 'bg-red-600 text-white dark:bg-red-500 ',
warning: 'bg-yellow-600 dark:bg-yellow-500 text-white',
info: " bg-blue-600 dark:bg-pavitra-blue text-white ",
info: ' bg-blue-600 dark:bg-pavitra-blue text-white ',
},
bgHover: {
white: 'hover:bg-gray-100',
@ -89,7 +92,7 @@ export const getButtonColor = (
'hover:bg-red-700 hover:border-red-700 hover:dark:bg-red-600 hover:dark:border-red-600',
warning:
'hover:bg-yellow-700 hover:border-yellow-700 hover:dark:bg-yellow-600 hover:dark:border-yellow-600',
info: "hover:bg-blue-700 hover:border-blue-700 hover:dark:bg-pavitra-blue/80 hover:dark:border-pavitra-blue/80",
info: 'hover:bg-blue-700 hover:border-blue-700 hover:dark:bg-pavitra-blue/80 hover:dark:border-pavitra-blue/80',
},
borders: {
white: 'border-white',
@ -99,7 +102,7 @@ export const getButtonColor = (
success: 'border-emerald-600 dark:border-pavitra-blue',
danger: 'border-red-600 dark:border-red-500',
warning: 'border-yellow-600 dark:border-yellow-500',
info: "border-blue-600 border-blue-600 dark:border-pavitra-blue",
info: 'border-blue-600 border-blue-600 dark:border-pavitra-blue',
},
text: {
contrast: 'dark:text-slate-100',
@ -111,28 +114,32 @@ export const getButtonColor = (
outlineHover: {
contrast:
'hover:bg-gray-800 hover:text-gray-100 hover:dark:bg-slate-100 hover:dark:text-black',
success: 'hover:bg-emerald-600 hover:text-white hover:text-white hover:dark:text-white hover:dark:border-pavitra-blue',
success:
'hover:bg-emerald-600 hover:text-white hover:text-white hover:dark:text-white hover:dark:border-pavitra-blue',
danger:
'hover:bg-red-600 hover:text-white hover:text-white hover:dark:text-white hover:dark:border-red-600',
warning:
'hover:bg-yellow-600 hover:text-white hover:text-white hover:dark:text-white hover:dark:border-yellow-600',
info: "hover:bg-blue-600 hover:bg-blue-600 hover:text-white hover:dark:text-white hover:dark:border-pavitra-blue",
info: 'hover:bg-blue-600 hover:bg-blue-600 hover:text-white hover:dark:text-white hover:dark:border-pavitra-blue',
},
}
};
const isOutlinedProcessed = isOutlined && ['white', 'whiteDark', 'lightDark'].indexOf(color) < 0
const isOutlinedProcessed =
isOutlined && ['white', 'whiteDark', 'lightDark'].indexOf(color) < 0;
const base = [colors.borders[color], colors.ring[color]]
const base = [colors.borders[color], colors.ring[color]];
if (isActive) {
base.push(colors.active[color])
base.push(colors.active[color]);
} else {
base.push(isOutlinedProcessed ? colors.text[color] : colors.bg[color])
base.push(isOutlinedProcessed ? colors.text[color] : colors.bg[color]);
}
if (hasHover) {
base.push(isOutlinedProcessed ? colors.outlineHover[color] : colors.bgHover[color])
base.push(
isOutlinedProcessed ? colors.outlineHover[color] : colors.bgHover[color],
);
}
return base.join(' ')
}
return base.join(' ');
};

View File

@ -4,12 +4,11 @@ import ListActionsPopover from '../ListActionsPopover';
import { useAppSelector } from '../../stores/hooks';
import dataFormatter from '../../helpers/dataFormatter';
import { Pagination } from '../Pagination';
import {saveFile} from "../../helpers/fileSaver";
import LoadingSpinner from "../LoadingSpinner";
import { saveFile } from '../../helpers/fileSaver';
import LoadingSpinner from '../LoadingSpinner';
import Link from 'next/link';
import {hasPermission} from "../../helpers/userPermissions";
import { hasPermission } from '../../helpers/userPermissions';
type Props = {
access_logs: any[];
@ -37,8 +36,7 @@ const CardAccess_logs = ({
const focusRing = useAppSelector((state) => state.style.focusRingColor);
const currentUser = useAppSelector((state) => state.auth.currentUser);
const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_ACCESS_LOGS')
const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_ACCESS_LOGS');
return (
<div className={'p-4'}>
@ -47,38 +45,39 @@ const CardAccess_logs = ({
role='list'
className='grid grid-cols-1 gap-x-6 gap-y-8 lg:grid-cols-3 2xl:grid-cols-4 xl:gap-x-8'
>
{!loading && access_logs.map((item, index) => (
{!loading &&
access_logs.map((item, index) => (
<li
key={item.id}
className={`overflow-hidden ${corners !== 'rounded-full' ? corners : 'rounded-3xl'} border ${focusRing} border-gray-200 dark:border-dark-700 ${
darkMode ? 'aside-scrollbars-[slate]' : asideScrollbarsStyle
}`}
>
<div className={`flex items-center ${bgColor} p-6 gap-x-4 border-b border-gray-900/5 bg-gray-50 dark:bg-dark-800 relative`}>
<Link href={`/access_logs/access_logs-view/?id=${item.id}`} className='text-lg font-bold leading-6 line-clamp-1'>
<div
className={`flex items-center ${bgColor} p-6 gap-x-4 border-b border-gray-900/5 bg-gray-50 dark:bg-dark-800 relative`}
>
<Link
href={`/access_logs/access_logs-view/?id=${item.id}`}
className='text-lg font-bold leading-6 line-clamp-1'
>
{item.path}
</Link>
<div className='ml-auto '>
<ListActionsPopover
onDelete={onDelete}
itemId={item.id}
pathEdit={`/access_logs/access_logs-edit/?id=${item.id}`}
pathView={`/access_logs/access_logs-view/?id=${item.id}`}
hasUpdatePermission={hasUpdatePermission}
/>
</div>
</div>
<dl className='divide-y divide-stone-300 dark:divide-dark-700 px-6 py-4 text-sm leading-6 h-64 overflow-y-auto'>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Project</dt>
<dt className=' text-gray-500 dark:text-dark-600'>
Project
</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{dataFormatter.projectsOneListFormatter(item.project)}
@ -86,11 +85,10 @@ const CardAccess_logs = ({
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Environment</dt>
<dt className=' text-gray-500 dark:text-dark-600'>
Environment
</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{item.environment}
@ -98,9 +96,6 @@ const CardAccess_logs = ({
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>User</dt>
<dd className='flex items-start gap-x-2'>
@ -110,23 +105,17 @@ const CardAccess_logs = ({
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Path</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{ item.path }
</div>
<div className='font-medium line-clamp-4'>{item.path}</div>
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>IPaddress</dt>
<dt className=' text-gray-500 dark:text-dark-600'>
IPaddress
</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{item.ip_address}
@ -134,11 +123,10 @@ const CardAccess_logs = ({
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Useragent</dt>
<dt className=' text-gray-500 dark:text-dark-600'>
Useragent
</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{item.user_agent}
@ -146,20 +134,16 @@ const CardAccess_logs = ({
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Accessedat</dt>
<dt className=' text-gray-500 dark:text-dark-600'>
Accessedat
</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{dataFormatter.dateTimeFormatter(item.accessed_at)}
</div>
</dd>
</div>
</dl>
</li>
))}

View File

@ -2,15 +2,14 @@ import React from 'react';
import CardBox from '../CardBox';
import ImageField from '../ImageField';
import dataFormatter from '../../helpers/dataFormatter';
import {saveFile} from "../../helpers/fileSaver";
import ListActionsPopover from "../ListActionsPopover";
import {useAppSelector} from "../../stores/hooks";
import {Pagination} from "../Pagination";
import LoadingSpinner from "../LoadingSpinner";
import { saveFile } from '../../helpers/fileSaver';
import ListActionsPopover from '../ListActionsPopover';
import { useAppSelector } from '../../stores/hooks';
import { Pagination } from '../Pagination';
import LoadingSpinner from '../LoadingSpinner';
import Link from 'next/link';
import {hasPermission} from "../../helpers/userPermissions";
import { hasPermission } from '../../helpers/userPermissions';
type Props = {
access_logs: any[];
@ -21,96 +20,84 @@ type Props = {
onPageChange: (page: number) => void;
};
const ListAccess_logs = ({ access_logs, loading, onDelete, currentPage, numPages, onPageChange }: Props) => {
const ListAccess_logs = ({
access_logs,
loading,
onDelete,
currentPage,
numPages,
onPageChange,
}: Props) => {
const currentUser = useAppSelector((state) => state.auth.currentUser);
const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_ACCESS_LOGS')
const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_ACCESS_LOGS');
const corners = useAppSelector((state) => state.style.corners);
const bgColor = useAppSelector((state) => state.style.cardsColor);
return (
<>
<div className='relative overflow-x-auto p-4 space-y-4'>
{loading && <LoadingSpinner />}
{!loading && access_logs.map((item) => (
{!loading &&
access_logs.map((item) => (
<div key={item.id}>
<CardBox hasTable isList className={'rounded shadow-none'}>
<div className={`flex rounded dark:bg-dark-900 border border-stone-300 items-center overflow-hidden`}>
<div
className={`flex rounded dark:bg-dark-900 border border-stone-300 items-center overflow-hidden`}
>
<Link
href={`/access_logs/access_logs-view/?id=${item.id}`}
className={
'flex-1 px-4 py-6 h-24 flex divide-x-2 divide-stone-300 items-center overflow-hidden`}> dark:divide-dark-700 overflow-x-auto'
}
>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Project</p>
<p className={'line-clamp-2'}>{ dataFormatter.projectsOneListFormatter(item.project) }</p>
<p className={'line-clamp-2'}>
{dataFormatter.projectsOneListFormatter(item.project)}
</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Environment</p>
<p className={'line-clamp-2'}>{item.environment}</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>User</p>
<p className={'line-clamp-2'}>{ dataFormatter.usersOneListFormatter(item.user) }</p>
<p className={'line-clamp-2'}>
{dataFormatter.usersOneListFormatter(item.user)}
</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Path</p>
<p className={'line-clamp-2'}>{item.path}</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>IPaddress</p>
<p className={'line-clamp-2'}>{item.ip_address}</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Useragent</p>
<p className={'line-clamp-2'}>{item.user_agent}</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Accessedat</p>
<p className={'line-clamp-2'}>{ dataFormatter.dateTimeFormatter(item.accessed_at) }</p>
<p className={'line-clamp-2'}>
{dataFormatter.dateTimeFormatter(item.accessed_at)}
</p>
</div>
</Link>
<ListActionsPopover
onDelete={onDelete}
itemId={item.id}
pathEdit={`/access_logs/access_logs-edit/?id=${item.id}`}
pathView={`/access_logs/access_logs-view/?id=${item.id}`}
hasUpdatePermission={hasUpdatePermission}
/>
</div>
</CardBox>
@ -130,7 +117,7 @@ const ListAccess_logs = ({ access_logs, loading, onDelete, currentPage, numPages
/>
</div>
</>
)
);
};
export default ListAccess_logs
export default ListAccess_logs;

View File

@ -1,463 +1,48 @@
import React, { useEffect, useState, useMemo } from 'react'
import { createPortal } from 'react-dom';
import { ToastContainer, toast } from 'react-toastify';
import BaseButton from '../BaseButton'
import CardBoxModal from '../CardBoxModal'
import CardBox from "../CardBox";
import { fetch, update, deleteItem, setRefetch, deleteItemsByIds } from '../../stores/access_logs/access_logsSlice'
import { useAppDispatch, useAppSelector } from '../../stores/hooks'
import { useRouter } from 'next/router'
import { Field, Form, Formik } from "formik";
/**
* Access Logs Table Component
*/
import React from 'react';
import GenericTable from '../Generic/GenericTable';
import {
DataGrid,
GridColDef,
} from '@mui/x-data-grid';
import {loadColumns} from "./configureAccess_logsCols";
import _ from 'lodash';
import dataFormatter from '../../helpers/dataFormatter'
import {dataGridStyles} from "../../styles";
fetch,
update,
deleteItem,
setRefetch,
deleteItemsByIds,
} from '../../stores/access_logs/access_logsSlice';
import { loadColumns } from './configureAccess_logsCols';
import type { AccessLog } from '../../types/entities';
import type { RootState } from '../../stores/store';
import type { Filter, FilterItem } from '../../types/filters';
const perPage = 10
const TableSampleAccess_logs = ({ filterItems, setFilterItems, filters, showGrid }) => {
const notify = (type, msg) => toast( msg, {type, position: "bottom-center"});
const dispatch = useAppDispatch();
const router = useRouter();
const pagesList = [];
const [id, setId] = useState(null);
const [currentPage, setCurrentPage] = useState(0);
const [filterRequest, setFilterRequest] = React.useState('');
const [columns, setColumns] = useState<GridColDef[]>([]);
const [selectedRows, setSelectedRows] = useState([]);
const [sortModel, setSortModel] = useState([
{
field: '',
sort: 'desc',
},
]);
const { access_logs, loading, count, notify: access_logsNotify, refetch } = useAppSelector((state) => state.access_logs)
const { currentUser } = useAppSelector((state) => state.auth);
const focusRing = useAppSelector((state) => state.style.focusRingColor);
const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
const corners = useAppSelector((state) => state.style.corners);
const numPages = Math.floor(count / perPage) === 0 ? 1 : Math.ceil(count / perPage);
for (let i = 0; i < numPages; i++) {
pagesList.push(i);
interface TableAccess_logsProps {
filterItems: FilterItem[];
setFilterItems: (items: FilterItem[]) => void;
filters: Filter[];
showGrid?: boolean;
}
const loadData = async (page = currentPage, request = filterRequest) => {
if (page !== currentPage) setCurrentPage(page);
if (request !== filterRequest) setFilterRequest(request);
const { sort, field } = sortModel[0];
const query = `?page=${page}&limit=${perPage}${request}&sort=${sort}&field=${field}`;
dispatch(fetch({ limit: perPage, page, query }));
};
useEffect(() => {
if (access_logsNotify.showNotification) {
notify(access_logsNotify.typeNotification, access_logsNotify.textNotification);
}
}, [access_logsNotify.showNotification]);
useEffect(() => {
if (!currentUser) return;
loadData();
}, [sortModel, currentUser]);
useEffect(() => {
if (refetch) {
loadData(0);
dispatch(setRefetch(false));
}
}, [refetch, dispatch]);
const [isModalInfoActive, setIsModalInfoActive] = useState(false)
const [isModalTrashActive, setIsModalTrashActive] = useState(false)
const handleModalAction = () => {
setIsModalInfoActive(false)
setIsModalTrashActive(false)
}
const handleDeleteModalAction = (id: string) => {
setId(id)
setIsModalTrashActive(true)
}
const handleDeleteAction = async () => {
if (id) {
await dispatch(deleteItem(id));
await loadData(0);
setIsModalTrashActive(false);
}
};
const generateFilterRequests = useMemo(() => {
let request = '&';
filterItems.forEach((item) => {
const isRangeFilter = filters.find(
(filter) =>
filter.title === item.fields.selectedField &&
(filter.number || filter.date),
);
if (isRangeFilter) {
const from = item.fields.filterValueFrom;
const to = item.fields.filterValueTo;
if (from) {
request += `${item.fields.selectedField}Range=${from}&`;
}
if (to) {
request += `${item.fields.selectedField}Range=${to}&`;
}
} else {
const value = item.fields.filterValue;
if (value) {
request += `${item.fields.selectedField}=${value}&`;
}
}
});
return request;
}, [filterItems, filters]);
const deleteFilter = (value) => {
const newItems = filterItems.filter((item) => item.id !== value);
if (newItems.length) {
setFilterItems(newItems);
} else {
loadData(0, '');
setFilterItems(newItems);
}
};
const handleSubmit = () => {
loadData(0, generateFilterRequests);
};
const handleChange = (id) => (e) => {
const value = e.target.value;
const name = e.target.name;
setFilterItems(
filterItems.map((item) => {
if (item.id !== id) return item;
if (name === 'selectedField') return { id, fields: { [name]: value } };
return { id, fields: { ...item.fields, [name]: value } }
}),
const TableAccess_logs: React.FC<TableAccess_logsProps> = ({
filterItems,
setFilterItems,
filters,
}) => {
return (
<GenericTable<AccessLog>
entityName='access_logs'
sliceSelector={(state: RootState) => state.access_logs}
fetchAction={fetch}
updateAction={update}
deleteAction={deleteItem}
deleteByIdsAction={deleteItemsByIds}
setRefetchAction={setRefetch}
loadColumnsFunction={loadColumns}
filters={filters}
filterItems={filterItems}
setFilterItems={setFilterItems}
/>
);
};
const handleReset = () => {
setFilterItems([]);
loadData(0, '');
};
const onPageChange = (page: number) => {
loadData(page);
setCurrentPage(page);
};
useEffect(() => {
if (!currentUser) return;
loadColumns(
handleDeleteModalAction,
`access_logs`,
currentUser,
).then((newCols) => setColumns(newCols));
}, [currentUser]);
const handleTableSubmit = async (id: string, data) => {
if (!_.isEmpty(data)) {
await dispatch(update({ id, data }))
.unwrap()
.then((res) => res)
.catch((err) => {
throw new Error(err);
});
}
};
const onDeleteRows = async (selectedRows) => {
await dispatch(deleteItemsByIds(selectedRows));
await loadData(0);
};
const controlClasses =
'w-full py-2 px-2 my-2 rounded dark:placeholder-gray-400 ' +
` ${bgColor} ${focusRing} ${corners} ` +
'dark:bg-slate-800 border';
const dataGrid = (
<div className='relative overflow-x-auto'>
<DataGrid
autoHeight
rowHeight={64}
sx={dataGridStyles}
className={'datagrid--table'}
getRowClassName={() => `datagrid--row`}
rows={access_logs ?? []}
columns={columns}
initialState={{
pagination: {
paginationModel: {
pageSize: 10,
},
},
}}
disableRowSelectionOnClick
onProcessRowUpdateError={(params) => {
console.log('Error', params);
}}
processRowUpdate={async (newRow, oldRow) => {
const data = dataFormatter.dataGridEditFormatter(newRow);
try {
await handleTableSubmit(newRow.id, data);
return newRow;
} catch {
return oldRow;
}
}}
sortingMode={'server'}
checkboxSelection
onRowSelectionModelChange={(ids) => {
setSelectedRows(ids)
}}
onSortModelChange={(params) => {
params.length
? setSortModel(params)
: setSortModel([{ field: '', sort: 'desc' }]);
}}
rowCount={count}
pageSizeOptions={[10]}
paginationMode={'server'}
loading={loading}
onPaginationModelChange={(params) => {
onPageChange(params.page);
}}
/>
</div>
)
return (
<>
{filterItems && Array.isArray( filterItems ) && filterItems.length ?
<CardBox>
<Formik
initialValues={{
checkboxes: ['lorem'],
switches: ['lorem'],
radio: 'lorem',
}}
onSubmit={() => null}
>
<Form>
<>
{filterItems && filterItems.map((filterItem) => {
return (
<div key={filterItem.id} className="flex mb-4">
<div className="flex flex-col w-full mr-3">
<div className=" text-gray-500 font-bold">Filter</div>
<Field
className={controlClasses}
name='selectedField'
id='selectedField'
component='select'
value={filterItem?.fields?.selectedField || ''}
onChange={handleChange(filterItem.id)}
>
{filters.map((selectOption) => (
<option
key={selectOption.title}
value={`${selectOption.title}`}
>
{selectOption.label}
</option>
))}
</Field>
</div>
{filters.find((filter) =>
filter.title === filterItem?.fields?.selectedField
)?.type === 'enum' ? (
<div className="flex flex-col w-full mr-3">
<div className="text-gray-500 font-bold">
Value
</div>
<Field
className={controlClasses}
name="filterValue"
id='filterValue'
component="select"
value={filterItem?.fields?.filterValue || ''}
onChange={handleChange(filterItem.id)}
>
<option value="">Select Value</option>
{filters.find((filter) =>
filter.title === filterItem?.fields?.selectedField
)?.options?.map((option) => (
<option key={option} value={option}>
{option}
</option>
))}
</Field>
</div>
) : filters.find((filter) =>
filter.title === filterItem?.fields?.selectedField
)?.number ? (
<div className="flex flex-row w-full mr-3">
<div className="flex flex-col w-full mr-3">
<div className=" text-gray-500 font-bold">From</div>
<Field
className={controlClasses}
name='filterValueFrom'
placeholder='From'
id='filterValueFrom'
value={filterItem?.fields?.filterValueFrom || ''}
onChange={handleChange(filterItem.id)}
/>
</div>
<div className="flex flex-col w-full">
<div className=" text-gray-500 font-bold">To</div>
<Field
className={controlClasses}
name='filterValueTo'
placeholder='to'
id='filterValueTo'
value={filterItem?.fields?.filterValueTo || ''}
onChange={handleChange(filterItem.id)}
/>
</div>
</div>
) : filters.find(
(filter) =>
filter.title ===
filterItem?.fields?.selectedField
)?.date ? (
<div className='flex flex-row w-full mr-3'>
<div className='flex flex-col w-full mr-3'>
<div className=' text-gray-500 font-bold'>
From
</div>
<Field
className={controlClasses}
name='filterValueFrom'
placeholder='From'
id='filterValueFrom'
type='datetime-local'
value={filterItem?.fields?.filterValueFrom || ''}
onChange={handleChange(filterItem.id)}
/>
</div>
<div className='flex flex-col w-full'>
<div className=' text-gray-500 font-bold'>To</div>
<Field
className={controlClasses}
name='filterValueTo'
placeholder='to'
id='filterValueTo'
type='datetime-local'
value={filterItem?.fields?.filterValueTo || ''}
onChange={handleChange(filterItem.id)}
/>
</div>
</div>
) : (
<div className="flex flex-col w-full mr-3">
<div className=" text-gray-500 font-bold">Contains</div>
<Field
className={controlClasses}
name='filterValue'
placeholder='Contained'
id='filterValue'
value={filterItem?.fields?.filterValue || ''}
onChange={handleChange(filterItem.id)}
/>
</div>
)}
<div className="flex flex-col">
<div className=" text-gray-500 font-bold">Action</div>
<BaseButton
className="my-2"
type='reset'
color='danger'
label='Delete'
onClick={() => {
deleteFilter(filterItem.id)
}}
/>
</div>
</div>
)
})}
<div className="flex">
<BaseButton
className="my-2 mr-3"
color="success"
label='Apply'
onClick={handleSubmit}
/>
<BaseButton
className="my-2"
color='info'
label='Cancel'
onClick={handleReset}
/>
</div>
</>
</Form>
</Formik>
</CardBox> : null
}
<CardBoxModal
title="Please confirm"
buttonColor="info"
buttonLabel={loading ? 'Deleting...' : 'Confirm'}
isActive={isModalTrashActive}
onConfirm={handleDeleteAction}
onCancel={handleModalAction}
>
<p>Are you sure you want to delete this item?</p>
</CardBoxModal>
{dataGrid}
{selectedRows.length > 0 &&
createPortal(
<BaseButton
className='me-4'
color='danger'
label={`Delete ${selectedRows.length === 1 ? 'Row' : 'Rows'}`}
onClick={() => onDeleteRows(selectedRows)}
/>,
document.getElementById('delete-rows-button'),
)}
<ToastContainer />
</>
)
}
export default TableSampleAccess_logs
export default TableAccess_logs;

View File

@ -8,12 +8,12 @@ import {
GridValueGetterParams,
} from '@mui/x-data-grid';
import ImageField from '../ImageField';
import {saveFile} from "../../helpers/fileSaver";
import dataFormatter from '../../helpers/dataFormatter'
import DataGridMultiSelect from "../DataGridMultiSelect";
import { saveFile } from '../../helpers/fileSaver';
import dataFormatter from '../../helpers/dataFormatter';
import DataGridMultiSelect from '../DataGridMultiSelect';
import ListActionsPopover from '../ListActionsPopover';
import {hasPermission} from "../../helpers/userPermissions";
import { hasPermission } from '../../helpers/userPermissions';
type Params = (id: string) => void;
@ -21,11 +21,9 @@ export const loadColumns = async (
onDelete: Params,
entityName: string,
user
user,
) => {
async function callOptionsApi(entityName: string) {
if (!hasPermission(user, 'READ_' + entityName.toUpperCase())) return [];
try {
@ -37,10 +35,9 @@ export const loadColumns = async (
}
}
const hasUpdatePermission = hasPermission(user, 'UPDATE_ACCESS_LOGS')
const hasUpdatePermission = hasPermission(user, 'UPDATE_ACCESS_LOGS');
return [
{
field: 'project',
headerName: 'Project',
@ -50,7 +47,6 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
sortable: false,
@ -60,7 +56,6 @@ export const loadColumns = async (
valueOptions: await callOptionsApi('projects'),
valueGetter: (params: GridValueGetterParams) =>
params?.value?.id ?? params?.value,
},
{
@ -72,10 +67,7 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
},
{
@ -87,7 +79,6 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
sortable: false,
@ -97,7 +88,6 @@ export const loadColumns = async (
valueOptions: await callOptionsApi('users'),
valueGetter: (params: GridValueGetterParams) =>
params?.value?.id ?? params?.value,
},
{
@ -109,10 +99,7 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
},
{
@ -124,10 +111,7 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
},
{
@ -139,10 +123,7 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
},
{
@ -154,13 +135,11 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
type: 'dateTime',
valueGetter: (params: GridValueGetterParams) =>
new Date(params.row.accessed_at),
},
{
@ -170,7 +149,6 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
getActions: (params: GridRowParams) => {
return [
<div key={params?.row?.id}>
<ListActionsPopover
@ -178,12 +156,10 @@ export const loadColumns = async (
itemId={params?.row?.id}
pathEdit={`/access_logs/access_logs-edit/?id=${params?.row?.id}`}
pathView={`/access_logs/access_logs-view/?id=${params?.row?.id}`}
hasUpdatePermission={hasUpdatePermission}
/>
</div>,
]
];
},
},
];

View File

@ -1,14 +1,14 @@
import React from 'react'
import { MenuAsideItem } from '../interfaces'
import AsideMenuLayer from './AsideMenuLayer'
import OverlayLayer from './OverlayLayer'
import React from 'react';
import { MenuAsideItem } from '../interfaces';
import AsideMenuLayer from './AsideMenuLayer';
import OverlayLayer from './OverlayLayer';
type Props = {
menu: MenuAsideItem[]
isAsideMobileExpanded: boolean
isAsideLgActive: boolean
onAsideLgClose: () => void
}
menu: MenuAsideItem[];
isAsideMobileExpanded: boolean;
isAsideLgActive: boolean;
onAsideLgClose: () => void;
};
export default function AsideMenu({
isAsideMobileExpanded = false,
@ -24,7 +24,9 @@ export default function AsideMenu({
}`}
onAsideLgCloseClick={props.onAsideLgClose}
/>
{isAsideLgActive && <OverlayLayer zIndex="z-30" onClick={props.onAsideLgClose} />}
{isAsideLgActive && (
<OverlayLayer zIndex='z-30' onClick={props.onAsideLgClose} />
)}
</>
)
);
}

View File

@ -1,49 +1,60 @@
import React, { useEffect, useState } from 'react'
import { mdiMinus, mdiPlus } from '@mdi/js'
import BaseIcon from './BaseIcon'
import Link from 'next/link'
import { getButtonColor } from '../colors'
import AsideMenuList from './AsideMenuList'
import { MenuAsideItem } from '../interfaces'
import { useAppSelector } from '../stores/hooks'
import { useRouter } from 'next/router'
import React, { useEffect, useState } from 'react';
import { mdiMinus, mdiPlus } from '@mdi/js';
import BaseIcon from './BaseIcon';
import Link from 'next/link';
import { getButtonColor } from '../colors';
import AsideMenuList from './AsideMenuList';
import { MenuAsideItem } from '../interfaces';
import { useAppSelector } from '../stores/hooks';
import { useRouter } from 'next/router';
type Props = {
item: MenuAsideItem
isDropdownList?: boolean
}
item: MenuAsideItem;
isDropdownList?: boolean;
};
const AsideMenuItem = ({ item, isDropdownList = false }: Props) => {
const [isLinkActive, setIsLinkActive] = useState(false)
const [isDropdownActive, setIsDropdownActive] = useState(false)
const [isLinkActive, setIsLinkActive] = useState(false);
const [isDropdownActive, setIsDropdownActive] = useState(false);
const asideMenuItemStyle = useAppSelector((state) => state.style.asideMenuItemStyle)
const asideMenuDropdownStyle = useAppSelector((state) => state.style.asideMenuDropdownStyle)
const asideMenuItemActiveStyle = useAppSelector((state) => state.style.asideMenuItemActiveStyle)
const asideMenuItemStyle = useAppSelector(
(state) => state.style.asideMenuItemStyle,
);
const asideMenuDropdownStyle = useAppSelector(
(state) => state.style.asideMenuDropdownStyle,
);
const asideMenuItemActiveStyle = useAppSelector(
(state) => state.style.asideMenuItemActiveStyle,
);
const borders = useAppSelector((state) => state.style.borders);
const activeLinkColor = useAppSelector(
(state) => state.style.activeLinkColor,
);
const activeClassAddon = !item.color && isLinkActive ? asideMenuItemActiveStyle : ''
const activeClassAddon =
!item.color && isLinkActive ? asideMenuItemActiveStyle : '';
const { asPath, isReady } = useRouter()
const { asPath, isReady } = useRouter();
useEffect(() => {
if (item.href && isReady) {
const linkPathName = new URL(item.href, location.href).pathname + '/';
const activePathname = new URL(asPath, location.href).pathname
const activePathname = new URL(asPath, location.href).pathname;
const activeView = activePathname.split('/')[1];
const linkPathNameView = linkPathName.split('/')[1];
setIsLinkActive(linkPathNameView === activeView);
}
}, [item.href, isReady, asPath])
}, [item.href, isReady, asPath]);
const asideMenuItemInnerContents = (
<>
{item.icon && (
<BaseIcon path={item.icon} className={`flex-none mx-3 ${activeClassAddon}`} size="18" />
<BaseIcon
path={item.icon}
className={`flex-none mx-3 ${activeClassAddon}`}
size='18'
/>
)}
<span
className={`grow text-ellipsis line-clamp-1 ${
@ -56,11 +67,11 @@ const AsideMenuItem = ({ item, isDropdownList = false }: Props) => {
<BaseIcon
path={isDropdownActive ? mdiMinus : mdiPlus}
className={`flex-none ${activeClassAddon}`}
w="w-12"
w='w-12'
/>
)}
</>
)
);
const componentClass = [
'flex cursor-pointer py-1.5 ',
@ -82,7 +93,10 @@ const AsideMenuItem = ({ item, isDropdownList = false }: Props) => {
</Link>
)}
{!item.href && (
<div className={componentClass} onClick={() => setIsDropdownActive(!isDropdownActive)}>
<div
className={componentClass}
onClick={() => setIsDropdownActive(!isDropdownActive)}
>
{asideMenuItemInnerContents}
</div>
)}
@ -96,7 +110,7 @@ const AsideMenuItem = ({ item, isDropdownList = false }: Props) => {
/>
)}
</li>
)
}
);
};
export default AsideMenuItem
export default AsideMenuItem;

View File

@ -1,30 +1,36 @@
import React from 'react'
import { mdiLogout, mdiClose } from '@mdi/js'
import BaseIcon from './BaseIcon'
import AsideMenuList from './AsideMenuList'
import { MenuAsideItem } from '../interfaces'
import { useAppSelector } from '../stores/hooks'
import React from 'react';
import { mdiLogout, mdiClose } from '@mdi/js';
import BaseIcon from './BaseIcon';
import AsideMenuList from './AsideMenuList';
import { MenuAsideItem } from '../interfaces';
import { useAppSelector } from '../stores/hooks';
import Link from 'next/link';
type Props = {
menu: MenuAsideItem[]
className?: string
onAsideLgCloseClick: () => void
}
menu: MenuAsideItem[];
className?: string;
onAsideLgCloseClick: () => void;
};
export default function AsideMenuLayer({ menu, className = '', ...props }: Props) {
export default function AsideMenuLayer({
menu,
className = '',
...props
}: Props) {
const corners = useAppSelector((state) => state.style.corners);
const asideStyle = useAppSelector((state) => state.style.asideStyle)
const asideBrandStyle = useAppSelector((state) => state.style.asideBrandStyle)
const asideScrollbarsStyle = useAppSelector((state) => state.style.asideScrollbarsStyle)
const darkMode = useAppSelector((state) => state.style.darkMode)
const asideStyle = useAppSelector((state) => state.style.asideStyle);
const asideBrandStyle = useAppSelector(
(state) => state.style.asideBrandStyle,
);
const asideScrollbarsStyle = useAppSelector(
(state) => state.style.asideScrollbarsStyle,
);
const darkMode = useAppSelector((state) => state.style.darkMode);
const handleAsideLgCloseClick = (e: React.MouseEvent) => {
e.preventDefault()
props.onAsideLgCloseClick()
}
e.preventDefault();
props.onAsideLgCloseClick();
};
return (
<aside
@ -37,14 +43,11 @@ export default function AsideMenuLayer({ menu, className = '', ...props }: Props
<div
className={`flex flex-row h-14 items-center justify-between ${asideBrandStyle}`}
>
<div className="text-center flex-1 lg:text-left lg:pl-6 xl:text-center xl:pl-0">
<b className="font-black">Shimahara Visual</b>
<div className='text-center flex-1 lg:text-left lg:pl-6 xl:text-center xl:pl-0'>
<b className='font-black'>Shimahara Visual</b>
</div>
<button
className="hidden lg:inline-block xl:hidden p-3"
className='hidden lg:inline-block xl:hidden p-3'
onClick={handleAsideLgCloseClick}
>
<BaseIcon path={mdiClose} />
@ -59,5 +62,5 @@ export default function AsideMenuLayer({ menu, className = '', ...props }: Props
</div>
</div>
</aside>
)
);
}

View File

@ -1,16 +1,20 @@
import React from 'react'
import { MenuAsideItem } from '../interfaces'
import AsideMenuItem from './AsideMenuItem'
import {useAppSelector} from "../stores/hooks";
import {hasPermission} from "../helpers/userPermissions";
import React from 'react';
import { MenuAsideItem } from '../interfaces';
import AsideMenuItem from './AsideMenuItem';
import { useAppSelector } from '../stores/hooks';
import { hasPermission } from '../helpers/userPermissions';
type Props = {
menu: MenuAsideItem[]
isDropdownList?: boolean
className?: string
}
menu: MenuAsideItem[];
isDropdownList?: boolean;
className?: string;
};
export default function AsideMenuList({ menu, isDropdownList = false, className = '' }: Props) {
export default function AsideMenuList({
menu,
isDropdownList = false,
className = '',
}: Props) {
const { currentUser } = useAppSelector((state) => state.auth);
if (!currentUser) return null;
@ -18,18 +22,14 @@ export default function AsideMenuList({ menu, isDropdownList = false, className
return (
<ul className={className}>
{menu.map((item, index) => {
if (!hasPermission(currentUser, item.permissions)) return null;
return (
<div key={index}>
<AsideMenuItem
item={item}
isDropdownList={isDropdownList}
/>
<AsideMenuItem item={item} isDropdownList={isDropdownList} />
</div>
)
);
})}
</ul>
)
);
}

View File

@ -4,12 +4,11 @@ import ListActionsPopover from '../ListActionsPopover';
import { useAppSelector } from '../../stores/hooks';
import dataFormatter from '../../helpers/dataFormatter';
import { Pagination } from '../Pagination';
import {saveFile} from "../../helpers/fileSaver";
import LoadingSpinner from "../LoadingSpinner";
import { saveFile } from '../../helpers/fileSaver';
import LoadingSpinner from '../LoadingSpinner';
import Link from 'next/link';
import {hasPermission} from "../../helpers/userPermissions";
import { hasPermission } from '../../helpers/userPermissions';
type Props = {
asset_variants: any[];
@ -37,8 +36,10 @@ const CardAsset_variants = ({
const focusRing = useAppSelector((state) => state.style.focusRingColor);
const currentUser = useAppSelector((state) => state.auth.currentUser);
const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_ASSET_VARIANTS')
const hasUpdatePermission = hasPermission(
currentUser,
'UPDATE_ASSET_VARIANTS',
);
return (
<div className={'p-4'}>
@ -47,36 +48,35 @@ const CardAsset_variants = ({
role='list'
className='grid grid-cols-1 gap-x-6 gap-y-8 lg:grid-cols-3 2xl:grid-cols-4 xl:gap-x-8'
>
{!loading && asset_variants.map((item, index) => (
{!loading &&
asset_variants.map((item, index) => (
<li
key={item.id}
className={`overflow-hidden ${corners !== 'rounded-full' ? corners : 'rounded-3xl'} border ${focusRing} border-gray-200 dark:border-dark-700 ${
darkMode ? 'aside-scrollbars-[slate]' : asideScrollbarsStyle
}`}
>
<div className={`flex items-center ${bgColor} p-6 gap-x-4 border-b border-gray-900/5 bg-gray-50 dark:bg-dark-800 relative`}>
<Link href={`/asset_variants/asset_variants-view/?id=${item.id}`} className='text-lg font-bold leading-6 line-clamp-1'>
<div
className={`flex items-center ${bgColor} p-6 gap-x-4 border-b border-gray-900/5 bg-gray-50 dark:bg-dark-800 relative`}
>
<Link
href={`/asset_variants/asset_variants-view/?id=${item.id}`}
className='text-lg font-bold leading-6 line-clamp-1'
>
{item.variant_type}
</Link>
<div className='ml-auto '>
<ListActionsPopover
onDelete={onDelete}
itemId={item.id}
pathEdit={`/asset_variants/asset_variants-edit/?id=${item.id}`}
pathView={`/asset_variants/asset_variants-view/?id=${item.id}`}
hasUpdatePermission={hasUpdatePermission}
/>
</div>
</div>
<dl className='divide-y divide-stone-300 dark:divide-dark-700 px-6 py-4 text-sm leading-6 h-64 overflow-y-auto'>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Asset</dt>
<dd className='flex items-start gap-x-2'>
@ -86,11 +86,10 @@ const CardAsset_variants = ({
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Varianttype</dt>
<dt className=' text-gray-500 dark:text-dark-600'>
Varianttype
</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{item.variant_type}
@ -98,11 +97,10 @@ const CardAsset_variants = ({
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>CDNURL</dt>
<dt className=' text-gray-500 dark:text-dark-600'>
CDNURL
</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{item.cdn_url}
@ -110,11 +108,10 @@ const CardAsset_variants = ({
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Width(px)</dt>
<dt className=' text-gray-500 dark:text-dark-600'>
Width(px)
</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{item.width_px}
@ -122,11 +119,10 @@ const CardAsset_variants = ({
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Height(px)</dt>
<dt className=' text-gray-500 dark:text-dark-600'>
Height(px)
</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{item.height_px}
@ -134,20 +130,16 @@ const CardAsset_variants = ({
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Size(MB)</dt>
<dt className=' text-gray-500 dark:text-dark-600'>
Size(MB)
</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{item.size_mb}
</div>
</dd>
</div>
</dl>
</li>
))}

View File

@ -2,15 +2,14 @@ import React from 'react';
import CardBox from '../CardBox';
import ImageField from '../ImageField';
import dataFormatter from '../../helpers/dataFormatter';
import {saveFile} from "../../helpers/fileSaver";
import ListActionsPopover from "../ListActionsPopover";
import {useAppSelector} from "../../stores/hooks";
import {Pagination} from "../Pagination";
import LoadingSpinner from "../LoadingSpinner";
import { saveFile } from '../../helpers/fileSaver';
import ListActionsPopover from '../ListActionsPopover';
import { useAppSelector } from '../../stores/hooks';
import { Pagination } from '../Pagination';
import LoadingSpinner from '../LoadingSpinner';
import Link from 'next/link';
import {hasPermission} from "../../helpers/userPermissions";
import { hasPermission } from '../../helpers/userPermissions';
type Props = {
asset_variants: any[];
@ -21,88 +20,78 @@ type Props = {
onPageChange: (page: number) => void;
};
const ListAsset_variants = ({ asset_variants, loading, onDelete, currentPage, numPages, onPageChange }: Props) => {
const ListAsset_variants = ({
asset_variants,
loading,
onDelete,
currentPage,
numPages,
onPageChange,
}: Props) => {
const currentUser = useAppSelector((state) => state.auth.currentUser);
const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_ASSET_VARIANTS')
const hasUpdatePermission = hasPermission(
currentUser,
'UPDATE_ASSET_VARIANTS',
);
const corners = useAppSelector((state) => state.style.corners);
const bgColor = useAppSelector((state) => state.style.cardsColor);
return (
<>
<div className='relative overflow-x-auto p-4 space-y-4'>
{loading && <LoadingSpinner />}
{!loading && asset_variants.map((item) => (
{!loading &&
asset_variants.map((item) => (
<div key={item.id}>
<CardBox hasTable isList className={'rounded shadow-none'}>
<div className={`flex rounded dark:bg-dark-900 border border-stone-300 items-center overflow-hidden`}>
<div
className={`flex rounded dark:bg-dark-900 border border-stone-300 items-center overflow-hidden`}
>
<Link
href={`/asset_variants/asset_variants-view/?id=${item.id}`}
className={
'flex-1 px-4 py-6 h-24 flex divide-x-2 divide-stone-300 items-center overflow-hidden`}> dark:divide-dark-700 overflow-x-auto'
}
>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Asset</p>
<p className={'line-clamp-2'}>{ dataFormatter.assetsOneListFormatter(item.asset) }</p>
<p className={'line-clamp-2'}>
{dataFormatter.assetsOneListFormatter(item.asset)}
</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Varianttype</p>
<p className={'line-clamp-2'}>{item.variant_type}</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>CDNURL</p>
<p className={'line-clamp-2'}>{item.cdn_url}</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Width(px)</p>
<p className={'line-clamp-2'}>{item.width_px}</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Height(px)</p>
<p className={'line-clamp-2'}>{item.height_px}</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Size(MB)</p>
<p className={'line-clamp-2'}>{item.size_mb}</p>
</div>
</Link>
<ListActionsPopover
onDelete={onDelete}
itemId={item.id}
pathEdit={`/asset_variants/asset_variants-edit/?id=${item.id}`}
pathView={`/asset_variants/asset_variants-view/?id=${item.id}`}
hasUpdatePermission={hasUpdatePermission}
/>
</div>
</CardBox>
@ -122,7 +111,7 @@ const ListAsset_variants = ({ asset_variants, loading, onDelete, currentPage, nu
/>
</div>
</>
)
);
};
export default ListAsset_variants
export default ListAsset_variants;

View File

@ -1,463 +1,48 @@
import React, { useEffect, useState, useMemo } from 'react'
import { createPortal } from 'react-dom';
import { ToastContainer, toast } from 'react-toastify';
import BaseButton from '../BaseButton'
import CardBoxModal from '../CardBoxModal'
import CardBox from "../CardBox";
import { fetch, update, deleteItem, setRefetch, deleteItemsByIds } from '../../stores/asset_variants/asset_variantsSlice'
import { useAppDispatch, useAppSelector } from '../../stores/hooks'
import { useRouter } from 'next/router'
import { Field, Form, Formik } from "formik";
/**
* Asset Variants Table Component
*/
import React from 'react';
import GenericTable from '../Generic/GenericTable';
import {
DataGrid,
GridColDef,
} from '@mui/x-data-grid';
import {loadColumns} from "./configureAsset_variantsCols";
import _ from 'lodash';
import dataFormatter from '../../helpers/dataFormatter'
import {dataGridStyles} from "../../styles";
fetch,
update,
deleteItem,
setRefetch,
deleteItemsByIds,
} from '../../stores/asset_variants/asset_variantsSlice';
import { loadColumns } from './configureAsset_variantsCols';
import type { AssetVariant } from '../../types/entities';
import type { RootState } from '../../stores/store';
import type { Filter, FilterItem } from '../../types/filters';
const perPage = 10
const TableSampleAsset_variants = ({ filterItems, setFilterItems, filters, showGrid }) => {
const notify = (type, msg) => toast( msg, {type, position: "bottom-center"});
const dispatch = useAppDispatch();
const router = useRouter();
const pagesList = [];
const [id, setId] = useState(null);
const [currentPage, setCurrentPage] = useState(0);
const [filterRequest, setFilterRequest] = React.useState('');
const [columns, setColumns] = useState<GridColDef[]>([]);
const [selectedRows, setSelectedRows] = useState([]);
const [sortModel, setSortModel] = useState([
{
field: '',
sort: 'desc',
},
]);
const { asset_variants, loading, count, notify: asset_variantsNotify, refetch } = useAppSelector((state) => state.asset_variants)
const { currentUser } = useAppSelector((state) => state.auth);
const focusRing = useAppSelector((state) => state.style.focusRingColor);
const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
const corners = useAppSelector((state) => state.style.corners);
const numPages = Math.floor(count / perPage) === 0 ? 1 : Math.ceil(count / perPage);
for (let i = 0; i < numPages; i++) {
pagesList.push(i);
interface TableAsset_variantsProps {
filterItems: FilterItem[];
setFilterItems: (items: FilterItem[]) => void;
filters: Filter[];
showGrid?: boolean;
}
const loadData = async (page = currentPage, request = filterRequest) => {
if (page !== currentPage) setCurrentPage(page);
if (request !== filterRequest) setFilterRequest(request);
const { sort, field } = sortModel[0];
const query = `?page=${page}&limit=${perPage}${request}&sort=${sort}&field=${field}`;
dispatch(fetch({ limit: perPage, page, query }));
};
useEffect(() => {
if (asset_variantsNotify.showNotification) {
notify(asset_variantsNotify.typeNotification, asset_variantsNotify.textNotification);
}
}, [asset_variantsNotify.showNotification]);
useEffect(() => {
if (!currentUser) return;
loadData();
}, [sortModel, currentUser]);
useEffect(() => {
if (refetch) {
loadData(0);
dispatch(setRefetch(false));
}
}, [refetch, dispatch]);
const [isModalInfoActive, setIsModalInfoActive] = useState(false)
const [isModalTrashActive, setIsModalTrashActive] = useState(false)
const handleModalAction = () => {
setIsModalInfoActive(false)
setIsModalTrashActive(false)
}
const handleDeleteModalAction = (id: string) => {
setId(id)
setIsModalTrashActive(true)
}
const handleDeleteAction = async () => {
if (id) {
await dispatch(deleteItem(id));
await loadData(0);
setIsModalTrashActive(false);
}
};
const generateFilterRequests = useMemo(() => {
let request = '&';
filterItems.forEach((item) => {
const isRangeFilter = filters.find(
(filter) =>
filter.title === item.fields.selectedField &&
(filter.number || filter.date),
);
if (isRangeFilter) {
const from = item.fields.filterValueFrom;
const to = item.fields.filterValueTo;
if (from) {
request += `${item.fields.selectedField}Range=${from}&`;
}
if (to) {
request += `${item.fields.selectedField}Range=${to}&`;
}
} else {
const value = item.fields.filterValue;
if (value) {
request += `${item.fields.selectedField}=${value}&`;
}
}
});
return request;
}, [filterItems, filters]);
const deleteFilter = (value) => {
const newItems = filterItems.filter((item) => item.id !== value);
if (newItems.length) {
setFilterItems(newItems);
} else {
loadData(0, '');
setFilterItems(newItems);
}
};
const handleSubmit = () => {
loadData(0, generateFilterRequests);
};
const handleChange = (id) => (e) => {
const value = e.target.value;
const name = e.target.name;
setFilterItems(
filterItems.map((item) => {
if (item.id !== id) return item;
if (name === 'selectedField') return { id, fields: { [name]: value } };
return { id, fields: { ...item.fields, [name]: value } }
}),
const TableAsset_variants: React.FC<TableAsset_variantsProps> = ({
filterItems,
setFilterItems,
filters,
}) => {
return (
<GenericTable<AssetVariant>
entityName='asset_variants'
sliceSelector={(state: RootState) => state.asset_variants}
fetchAction={fetch}
updateAction={update}
deleteAction={deleteItem}
deleteByIdsAction={deleteItemsByIds}
setRefetchAction={setRefetch}
loadColumnsFunction={loadColumns}
filters={filters}
filterItems={filterItems}
setFilterItems={setFilterItems}
/>
);
};
const handleReset = () => {
setFilterItems([]);
loadData(0, '');
};
const onPageChange = (page: number) => {
loadData(page);
setCurrentPage(page);
};
useEffect(() => {
if (!currentUser) return;
loadColumns(
handleDeleteModalAction,
`asset_variants`,
currentUser,
).then((newCols) => setColumns(newCols));
}, [currentUser]);
const handleTableSubmit = async (id: string, data) => {
if (!_.isEmpty(data)) {
await dispatch(update({ id, data }))
.unwrap()
.then((res) => res)
.catch((err) => {
throw new Error(err);
});
}
};
const onDeleteRows = async (selectedRows) => {
await dispatch(deleteItemsByIds(selectedRows));
await loadData(0);
};
const controlClasses =
'w-full py-2 px-2 my-2 rounded dark:placeholder-gray-400 ' +
` ${bgColor} ${focusRing} ${corners} ` +
'dark:bg-slate-800 border';
const dataGrid = (
<div className='relative overflow-x-auto'>
<DataGrid
autoHeight
rowHeight={64}
sx={dataGridStyles}
className={'datagrid--table'}
getRowClassName={() => `datagrid--row`}
rows={asset_variants ?? []}
columns={columns}
initialState={{
pagination: {
paginationModel: {
pageSize: 10,
},
},
}}
disableRowSelectionOnClick
onProcessRowUpdateError={(params) => {
console.log('Error', params);
}}
processRowUpdate={async (newRow, oldRow) => {
const data = dataFormatter.dataGridEditFormatter(newRow);
try {
await handleTableSubmit(newRow.id, data);
return newRow;
} catch {
return oldRow;
}
}}
sortingMode={'server'}
checkboxSelection
onRowSelectionModelChange={(ids) => {
setSelectedRows(ids)
}}
onSortModelChange={(params) => {
params.length
? setSortModel(params)
: setSortModel([{ field: '', sort: 'desc' }]);
}}
rowCount={count}
pageSizeOptions={[10]}
paginationMode={'server'}
loading={loading}
onPaginationModelChange={(params) => {
onPageChange(params.page);
}}
/>
</div>
)
return (
<>
{filterItems && Array.isArray( filterItems ) && filterItems.length ?
<CardBox>
<Formik
initialValues={{
checkboxes: ['lorem'],
switches: ['lorem'],
radio: 'lorem',
}}
onSubmit={() => null}
>
<Form>
<>
{filterItems && filterItems.map((filterItem) => {
return (
<div key={filterItem.id} className="flex mb-4">
<div className="flex flex-col w-full mr-3">
<div className=" text-gray-500 font-bold">Filter</div>
<Field
className={controlClasses}
name='selectedField'
id='selectedField'
component='select'
value={filterItem?.fields?.selectedField || ''}
onChange={handleChange(filterItem.id)}
>
{filters.map((selectOption) => (
<option
key={selectOption.title}
value={`${selectOption.title}`}
>
{selectOption.label}
</option>
))}
</Field>
</div>
{filters.find((filter) =>
filter.title === filterItem?.fields?.selectedField
)?.type === 'enum' ? (
<div className="flex flex-col w-full mr-3">
<div className="text-gray-500 font-bold">
Value
</div>
<Field
className={controlClasses}
name="filterValue"
id='filterValue'
component="select"
value={filterItem?.fields?.filterValue || ''}
onChange={handleChange(filterItem.id)}
>
<option value="">Select Value</option>
{filters.find((filter) =>
filter.title === filterItem?.fields?.selectedField
)?.options?.map((option) => (
<option key={option} value={option}>
{option}
</option>
))}
</Field>
</div>
) : filters.find((filter) =>
filter.title === filterItem?.fields?.selectedField
)?.number ? (
<div className="flex flex-row w-full mr-3">
<div className="flex flex-col w-full mr-3">
<div className=" text-gray-500 font-bold">From</div>
<Field
className={controlClasses}
name='filterValueFrom'
placeholder='From'
id='filterValueFrom'
value={filterItem?.fields?.filterValueFrom || ''}
onChange={handleChange(filterItem.id)}
/>
</div>
<div className="flex flex-col w-full">
<div className=" text-gray-500 font-bold">To</div>
<Field
className={controlClasses}
name='filterValueTo'
placeholder='to'
id='filterValueTo'
value={filterItem?.fields?.filterValueTo || ''}
onChange={handleChange(filterItem.id)}
/>
</div>
</div>
) : filters.find(
(filter) =>
filter.title ===
filterItem?.fields?.selectedField
)?.date ? (
<div className='flex flex-row w-full mr-3'>
<div className='flex flex-col w-full mr-3'>
<div className=' text-gray-500 font-bold'>
From
</div>
<Field
className={controlClasses}
name='filterValueFrom'
placeholder='From'
id='filterValueFrom'
type='datetime-local'
value={filterItem?.fields?.filterValueFrom || ''}
onChange={handleChange(filterItem.id)}
/>
</div>
<div className='flex flex-col w-full'>
<div className=' text-gray-500 font-bold'>To</div>
<Field
className={controlClasses}
name='filterValueTo'
placeholder='to'
id='filterValueTo'
type='datetime-local'
value={filterItem?.fields?.filterValueTo || ''}
onChange={handleChange(filterItem.id)}
/>
</div>
</div>
) : (
<div className="flex flex-col w-full mr-3">
<div className=" text-gray-500 font-bold">Contains</div>
<Field
className={controlClasses}
name='filterValue'
placeholder='Contained'
id='filterValue'
value={filterItem?.fields?.filterValue || ''}
onChange={handleChange(filterItem.id)}
/>
</div>
)}
<div className="flex flex-col">
<div className=" text-gray-500 font-bold">Action</div>
<BaseButton
className="my-2"
type='reset'
color='danger'
label='Delete'
onClick={() => {
deleteFilter(filterItem.id)
}}
/>
</div>
</div>
)
})}
<div className="flex">
<BaseButton
className="my-2 mr-3"
color="success"
label='Apply'
onClick={handleSubmit}
/>
<BaseButton
className="my-2"
color='info'
label='Cancel'
onClick={handleReset}
/>
</div>
</>
</Form>
</Formik>
</CardBox> : null
}
<CardBoxModal
title="Please confirm"
buttonColor="info"
buttonLabel={loading ? 'Deleting...' : 'Confirm'}
isActive={isModalTrashActive}
onConfirm={handleDeleteAction}
onCancel={handleModalAction}
>
<p>Are you sure you want to delete this item?</p>
</CardBoxModal>
{dataGrid}
{selectedRows.length > 0 &&
createPortal(
<BaseButton
className='me-4'
color='danger'
label={`Delete ${selectedRows.length === 1 ? 'Row' : 'Rows'}`}
onClick={() => onDeleteRows(selectedRows)}
/>,
document.getElementById('delete-rows-button'),
)}
<ToastContainer />
</>
)
}
export default TableSampleAsset_variants
export default TableAsset_variants;

View File

@ -8,12 +8,12 @@ import {
GridValueGetterParams,
} from '@mui/x-data-grid';
import ImageField from '../ImageField';
import {saveFile} from "../../helpers/fileSaver";
import dataFormatter from '../../helpers/dataFormatter'
import DataGridMultiSelect from "../DataGridMultiSelect";
import { saveFile } from '../../helpers/fileSaver';
import dataFormatter from '../../helpers/dataFormatter';
import DataGridMultiSelect from '../DataGridMultiSelect';
import ListActionsPopover from '../ListActionsPopover';
import {hasPermission} from "../../helpers/userPermissions";
import { hasPermission } from '../../helpers/userPermissions';
type Params = (id: string) => void;
@ -21,11 +21,9 @@ export const loadColumns = async (
onDelete: Params,
entityName: string,
user
user,
) => {
async function callOptionsApi(entityName: string) {
if (!hasPermission(user, 'READ_' + entityName.toUpperCase())) return [];
try {
@ -37,10 +35,9 @@ export const loadColumns = async (
}
}
const hasUpdatePermission = hasPermission(user, 'UPDATE_ASSET_VARIANTS')
const hasUpdatePermission = hasPermission(user, 'UPDATE_ASSET_VARIANTS');
return [
{
field: 'asset',
headerName: 'Asset',
@ -50,7 +47,6 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
sortable: false,
@ -60,7 +56,6 @@ export const loadColumns = async (
valueOptions: await callOptionsApi('assets'),
valueGetter: (params: GridValueGetterParams) =>
params?.value?.id ?? params?.value,
},
{
@ -72,10 +67,7 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
},
{
@ -87,10 +79,7 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
},
{
@ -102,11 +91,9 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
type: 'number',
},
{
@ -118,11 +105,9 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
type: 'number',
},
{
@ -134,11 +119,9 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
type: 'number',
},
{
@ -148,7 +131,6 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
getActions: (params: GridRowParams) => {
return [
<div key={params?.row?.id}>
<ListActionsPopover
@ -156,12 +138,10 @@ export const loadColumns = async (
itemId={params?.row?.id}
pathEdit={`/asset_variants/asset_variants-edit/?id=${params?.row?.id}`}
pathView={`/asset_variants/asset_variants-view/?id=${params?.row?.id}`}
hasUpdatePermission={hasUpdatePermission}
/>
</div>,
]
];
},
},
];

View File

@ -4,12 +4,11 @@ import ListActionsPopover from '../ListActionsPopover';
import { useAppSelector } from '../../stores/hooks';
import dataFormatter from '../../helpers/dataFormatter';
import { Pagination } from '../Pagination';
import {saveFile} from "../../helpers/fileSaver";
import LoadingSpinner from "../LoadingSpinner";
import { saveFile } from '../../helpers/fileSaver';
import LoadingSpinner from '../LoadingSpinner';
import Link from 'next/link';
import {hasPermission} from "../../helpers/userPermissions";
import { hasPermission } from '../../helpers/userPermissions';
type Props = {
assets: any[];
@ -37,8 +36,7 @@ const CardAssets = ({
const focusRing = useAppSelector((state) => state.style.focusRingColor);
const currentUser = useAppSelector((state) => state.auth.currentUser);
const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_ASSETS')
const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_ASSETS');
return (
<div className={'p-4'}>
@ -47,38 +45,39 @@ const CardAssets = ({
role='list'
className='grid grid-cols-1 gap-x-6 gap-y-8 lg:grid-cols-3 2xl:grid-cols-4 xl:gap-x-8'
>
{!loading && assets.map((item, index) => (
{!loading &&
assets.map((item, index) => (
<li
key={item.id}
className={`overflow-hidden ${corners !== 'rounded-full' ? corners : 'rounded-3xl'} border ${focusRing} border-gray-200 dark:border-dark-700 ${
darkMode ? 'aside-scrollbars-[slate]' : asideScrollbarsStyle
}`}
>
<div className={`flex items-center ${bgColor} p-6 gap-x-4 border-b border-gray-900/5 bg-gray-50 dark:bg-dark-800 relative`}>
<Link href={`/assets/assets-view/?id=${item.id}`} className='text-lg font-bold leading-6 line-clamp-1'>
<div
className={`flex items-center ${bgColor} p-6 gap-x-4 border-b border-gray-900/5 bg-gray-50 dark:bg-dark-800 relative`}
>
<Link
href={`/assets/assets-view/?id=${item.id}`}
className='text-lg font-bold leading-6 line-clamp-1'
>
{item.name}
</Link>
<div className='ml-auto '>
<ListActionsPopover
onDelete={onDelete}
itemId={item.id}
pathEdit={`/assets/assets-edit/?id=${item.id}`}
pathView={`/assets/assets-view/?id=${item.id}`}
hasUpdatePermission={hasUpdatePermission}
/>
</div>
</div>
<dl className='divide-y divide-stone-300 dark:divide-dark-700 px-6 py-4 text-sm leading-6 h-64 overflow-y-auto'>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Project</dt>
<dt className=' text-gray-500 dark:text-dark-600'>
Project
</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{dataFormatter.projectsOneListFormatter(item.project)}
@ -86,23 +85,17 @@ const CardAssets = ({
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Name</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{ item.name }
</div>
<div className='font-medium line-clamp-4'>{item.name}</div>
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Assettype</dt>
<dt className=' text-gray-500 dark:text-dark-600'>
Asset format
</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{item.asset_type}
@ -110,11 +103,19 @@ const CardAssets = ({
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Type</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{item.type || 'general'}
</div>
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>CDNURL</dt>
<dt className=' text-gray-500 dark:text-dark-600'>
CDNURL
</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{item.cdn_url}
@ -122,11 +123,10 @@ const CardAssets = ({
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Storagekey</dt>
<dt className=' text-gray-500 dark:text-dark-600'>
Storagekey
</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{item.storage_key}
@ -134,11 +134,10 @@ const CardAssets = ({
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>MIMEtype</dt>
<dt className=' text-gray-500 dark:text-dark-600'>
MIMEtype
</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{item.mime_type}
@ -146,11 +145,10 @@ const CardAssets = ({
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Size(MB)</dt>
<dt className=' text-gray-500 dark:text-dark-600'>
Size(MB)
</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{item.size_mb}
@ -158,11 +156,10 @@ const CardAssets = ({
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Width(px)</dt>
<dt className=' text-gray-500 dark:text-dark-600'>
Width(px)
</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{item.width_px}
@ -170,11 +167,10 @@ const CardAssets = ({
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Height(px)</dt>
<dt className=' text-gray-500 dark:text-dark-600'>
Height(px)
</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{item.height_px}
@ -182,11 +178,10 @@ const CardAssets = ({
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Duration(sec)</dt>
<dt className=' text-gray-500 dark:text-dark-600'>
Duration(sec)
</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{item.duration_sec}
@ -194,11 +189,10 @@ const CardAssets = ({
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Checksum</dt>
<dt className=' text-gray-500 dark:text-dark-600'>
Checksum
</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{item.checksum}
@ -206,11 +200,10 @@ const CardAssets = ({
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Ispublic</dt>
<dt className=' text-gray-500 dark:text-dark-600'>
Ispublic
</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{dataFormatter.booleanFormatter(item.is_public)}
@ -218,11 +211,10 @@ const CardAssets = ({
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Isdeleted</dt>
<dt className=' text-gray-500 dark:text-dark-600'>
Isdeleted
</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{dataFormatter.booleanFormatter(item.is_deleted)}
@ -230,20 +222,16 @@ const CardAssets = ({
</dd>
</div>
<div className='flex justify-between gap-x-4 py-3'>
<dt className=' text-gray-500 dark:text-dark-600'>Deletedat</dt>
<dt className=' text-gray-500 dark:text-dark-600'>
Deletedat
</dt>
<dd className='flex items-start gap-x-2'>
<div className='font-medium line-clamp-4'>
{dataFormatter.dateTimeFormatter(item.deleted_at_time)}
</div>
</dd>
</div>
</dl>
</li>
))}

View File

@ -2,15 +2,14 @@ import React from 'react';
import CardBox from '../CardBox';
import ImageField from '../ImageField';
import dataFormatter from '../../helpers/dataFormatter';
import {saveFile} from "../../helpers/fileSaver";
import ListActionsPopover from "../ListActionsPopover";
import {useAppSelector} from "../../stores/hooks";
import {Pagination} from "../Pagination";
import LoadingSpinner from "../LoadingSpinner";
import { saveFile } from '../../helpers/fileSaver';
import ListActionsPopover from '../ListActionsPopover';
import { useAppSelector } from '../../stores/hooks';
import { Pagination } from '../Pagination';
import LoadingSpinner from '../LoadingSpinner';
import Link from 'next/link';
import {hasPermission} from "../../helpers/userPermissions";
import { hasPermission } from '../../helpers/userPermissions';
type Props = {
assets: any[];
@ -21,152 +20,128 @@ type Props = {
onPageChange: (page: number) => void;
};
const ListAssets = ({ assets, loading, onDelete, currentPage, numPages, onPageChange }: Props) => {
const ListAssets = ({
assets,
loading,
onDelete,
currentPage,
numPages,
onPageChange,
}: Props) => {
const currentUser = useAppSelector((state) => state.auth.currentUser);
const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_ASSETS')
const hasUpdatePermission = hasPermission(currentUser, 'UPDATE_ASSETS');
const corners = useAppSelector((state) => state.style.corners);
const bgColor = useAppSelector((state) => state.style.cardsColor);
return (
<>
<div className='relative overflow-x-auto p-4 space-y-4'>
{loading && <LoadingSpinner />}
{!loading && assets.map((item) => (
{!loading &&
assets.map((item) => (
<div key={item.id}>
<CardBox hasTable isList className={'rounded shadow-none'}>
<div className={`flex rounded dark:bg-dark-900 border border-stone-300 items-center overflow-hidden`}>
<div
className={`flex rounded dark:bg-dark-900 border border-stone-300 items-center overflow-hidden`}
>
<Link
href={`/assets/assets-view/?id=${item.id}`}
className={
'flex-1 px-4 py-6 h-24 flex divide-x-2 divide-stone-300 items-center overflow-hidden`}> dark:divide-dark-700 overflow-x-auto'
}
>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Project</p>
<p className={'line-clamp-2'}>{ dataFormatter.projectsOneListFormatter(item.project) }</p>
<p className={'line-clamp-2'}>
{dataFormatter.projectsOneListFormatter(item.project)}
</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Name</p>
<p className={'line-clamp-2'}>{item.name}</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Assettype</p>
<p className={'text-xs text-gray-500 '}>Asset format</p>
<p className={'line-clamp-2'}>{item.asset_type}</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Type</p>
<p className={'line-clamp-2'}>{item.type || 'general'}</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>CDNURL</p>
<p className={'line-clamp-2'}>{item.cdn_url}</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Storagekey</p>
<p className={'line-clamp-2'}>{item.storage_key}</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>MIMEtype</p>
<p className={'line-clamp-2'}>{item.mime_type}</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Size(MB)</p>
<p className={'line-clamp-2'}>{item.size_mb}</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Width(px)</p>
<p className={'line-clamp-2'}>{item.width_px}</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Height(px)</p>
<p className={'line-clamp-2'}>{item.height_px}</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Duration(sec)</p>
<p className={'text-xs text-gray-500 '}>
Duration(sec)
</p>
<p className={'line-clamp-2'}>{item.duration_sec}</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Checksum</p>
<p className={'line-clamp-2'}>{item.checksum}</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Ispublic</p>
<p className={'line-clamp-2'}>{ dataFormatter.booleanFormatter(item.is_public) }</p>
<p className={'line-clamp-2'}>
{dataFormatter.booleanFormatter(item.is_public)}
</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Isdeleted</p>
<p className={'line-clamp-2'}>{ dataFormatter.booleanFormatter(item.is_deleted) }</p>
<p className={'line-clamp-2'}>
{dataFormatter.booleanFormatter(item.is_deleted)}
</p>
</div>
<div className={'flex-1 px-3'}>
<p className={'text-xs text-gray-500 '}>Deletedat</p>
<p className={'line-clamp-2'}>{ dataFormatter.dateTimeFormatter(item.deleted_at_time) }</p>
<p className={'line-clamp-2'}>
{dataFormatter.dateTimeFormatter(item.deleted_at_time)}
</p>
</div>
</Link>
<ListActionsPopover
onDelete={onDelete}
itemId={item.id}
pathEdit={`/assets/assets-edit/?id=${item.id}`}
pathView={`/assets/assets-view/?id=${item.id}`}
hasUpdatePermission={hasUpdatePermission}
/>
</div>
</CardBox>
@ -186,7 +161,7 @@ const ListAssets = ({ assets, loading, onDelete, currentPage, numPages, onPageCh
/>
</div>
</>
)
);
};
export default ListAssets
export default ListAssets;

View File

@ -1,463 +1,48 @@
import React, { useEffect, useState, useMemo } from 'react'
import { createPortal } from 'react-dom';
import { ToastContainer, toast } from 'react-toastify';
import BaseButton from '../BaseButton'
import CardBoxModal from '../CardBoxModal'
import CardBox from "../CardBox";
import { fetch, update, deleteItem, setRefetch, deleteItemsByIds } from '../../stores/assets/assetsSlice'
import { useAppDispatch, useAppSelector } from '../../stores/hooks'
import { useRouter } from 'next/router'
import { Field, Form, Formik } from "formik";
/**
* Assets Table Component
*/
import React from 'react';
import GenericTable from '../Generic/GenericTable';
import {
DataGrid,
GridColDef,
} from '@mui/x-data-grid';
import {loadColumns} from "./configureAssetsCols";
import _ from 'lodash';
import dataFormatter from '../../helpers/dataFormatter'
import {dataGridStyles} from "../../styles";
fetch,
update,
deleteItem,
setRefetch,
deleteItemsByIds,
} from '../../stores/assets/assetsSlice';
import { loadColumns } from './configureAssetsCols';
import type { Asset } from '../../types/entities';
import type { RootState } from '../../stores/store';
import type { Filter, FilterItem } from '../../types/filters';
const perPage = 10
const TableSampleAssets = ({ filterItems, setFilterItems, filters, showGrid }) => {
const notify = (type, msg) => toast( msg, {type, position: "bottom-center"});
const dispatch = useAppDispatch();
const router = useRouter();
const pagesList = [];
const [id, setId] = useState(null);
const [currentPage, setCurrentPage] = useState(0);
const [filterRequest, setFilterRequest] = React.useState('');
const [columns, setColumns] = useState<GridColDef[]>([]);
const [selectedRows, setSelectedRows] = useState([]);
const [sortModel, setSortModel] = useState([
{
field: '',
sort: 'desc',
},
]);
const { assets, loading, count, notify: assetsNotify, refetch } = useAppSelector((state) => state.assets)
const { currentUser } = useAppSelector((state) => state.auth);
const focusRing = useAppSelector((state) => state.style.focusRingColor);
const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
const corners = useAppSelector((state) => state.style.corners);
const numPages = Math.floor(count / perPage) === 0 ? 1 : Math.ceil(count / perPage);
for (let i = 0; i < numPages; i++) {
pagesList.push(i);
interface TableAssetsProps {
filterItems: FilterItem[];
setFilterItems: (items: FilterItem[]) => void;
filters: Filter[];
showGrid?: boolean;
}
const loadData = async (page = currentPage, request = filterRequest) => {
if (page !== currentPage) setCurrentPage(page);
if (request !== filterRequest) setFilterRequest(request);
const { sort, field } = sortModel[0];
const query = `?page=${page}&limit=${perPage}${request}&sort=${sort}&field=${field}`;
dispatch(fetch({ limit: perPage, page, query }));
};
useEffect(() => {
if (assetsNotify.showNotification) {
notify(assetsNotify.typeNotification, assetsNotify.textNotification);
}
}, [assetsNotify.showNotification]);
useEffect(() => {
if (!currentUser) return;
loadData();
}, [sortModel, currentUser]);
useEffect(() => {
if (refetch) {
loadData(0);
dispatch(setRefetch(false));
}
}, [refetch, dispatch]);
const [isModalInfoActive, setIsModalInfoActive] = useState(false)
const [isModalTrashActive, setIsModalTrashActive] = useState(false)
const handleModalAction = () => {
setIsModalInfoActive(false)
setIsModalTrashActive(false)
}
const handleDeleteModalAction = (id: string) => {
setId(id)
setIsModalTrashActive(true)
}
const handleDeleteAction = async () => {
if (id) {
await dispatch(deleteItem(id));
await loadData(0);
setIsModalTrashActive(false);
}
};
const generateFilterRequests = useMemo(() => {
let request = '&';
filterItems.forEach((item) => {
const isRangeFilter = filters.find(
(filter) =>
filter.title === item.fields.selectedField &&
(filter.number || filter.date),
);
if (isRangeFilter) {
const from = item.fields.filterValueFrom;
const to = item.fields.filterValueTo;
if (from) {
request += `${item.fields.selectedField}Range=${from}&`;
}
if (to) {
request += `${item.fields.selectedField}Range=${to}&`;
}
} else {
const value = item.fields.filterValue;
if (value) {
request += `${item.fields.selectedField}=${value}&`;
}
}
});
return request;
}, [filterItems, filters]);
const deleteFilter = (value) => {
const newItems = filterItems.filter((item) => item.id !== value);
if (newItems.length) {
setFilterItems(newItems);
} else {
loadData(0, '');
setFilterItems(newItems);
}
};
const handleSubmit = () => {
loadData(0, generateFilterRequests);
};
const handleChange = (id) => (e) => {
const value = e.target.value;
const name = e.target.name;
setFilterItems(
filterItems.map((item) => {
if (item.id !== id) return item;
if (name === 'selectedField') return { id, fields: { [name]: value } };
return { id, fields: { ...item.fields, [name]: value } }
}),
const TableAssets: React.FC<TableAssetsProps> = ({
filterItems,
setFilterItems,
filters,
}) => {
return (
<GenericTable<Asset>
entityName='assets'
sliceSelector={(state: RootState) => state.assets}
fetchAction={fetch}
updateAction={update}
deleteAction={deleteItem}
deleteByIdsAction={deleteItemsByIds}
setRefetchAction={setRefetch}
loadColumnsFunction={loadColumns}
filters={filters}
filterItems={filterItems}
setFilterItems={setFilterItems}
/>
);
};
const handleReset = () => {
setFilterItems([]);
loadData(0, '');
};
const onPageChange = (page: number) => {
loadData(page);
setCurrentPage(page);
};
useEffect(() => {
if (!currentUser) return;
loadColumns(
handleDeleteModalAction,
`assets`,
currentUser,
).then((newCols) => setColumns(newCols));
}, [currentUser]);
const handleTableSubmit = async (id: string, data) => {
if (!_.isEmpty(data)) {
await dispatch(update({ id, data }))
.unwrap()
.then((res) => res)
.catch((err) => {
throw new Error(err);
});
}
};
const onDeleteRows = async (selectedRows) => {
await dispatch(deleteItemsByIds(selectedRows));
await loadData(0);
};
const controlClasses =
'w-full py-2 px-2 my-2 rounded dark:placeholder-gray-400 ' +
` ${bgColor} ${focusRing} ${corners} ` +
'dark:bg-slate-800 border';
const dataGrid = (
<div className='relative overflow-x-auto'>
<DataGrid
autoHeight
rowHeight={64}
sx={dataGridStyles}
className={'datagrid--table'}
getRowClassName={() => `datagrid--row`}
rows={assets ?? []}
columns={columns}
initialState={{
pagination: {
paginationModel: {
pageSize: 10,
},
},
}}
disableRowSelectionOnClick
onProcessRowUpdateError={(params) => {
console.log('Error', params);
}}
processRowUpdate={async (newRow, oldRow) => {
const data = dataFormatter.dataGridEditFormatter(newRow);
try {
await handleTableSubmit(newRow.id, data);
return newRow;
} catch {
return oldRow;
}
}}
sortingMode={'server'}
checkboxSelection
onRowSelectionModelChange={(ids) => {
setSelectedRows(ids)
}}
onSortModelChange={(params) => {
params.length
? setSortModel(params)
: setSortModel([{ field: '', sort: 'desc' }]);
}}
rowCount={count}
pageSizeOptions={[10]}
paginationMode={'server'}
loading={loading}
onPaginationModelChange={(params) => {
onPageChange(params.page);
}}
/>
</div>
)
return (
<>
{filterItems && Array.isArray( filterItems ) && filterItems.length ?
<CardBox>
<Formik
initialValues={{
checkboxes: ['lorem'],
switches: ['lorem'],
radio: 'lorem',
}}
onSubmit={() => null}
>
<Form>
<>
{filterItems && filterItems.map((filterItem) => {
return (
<div key={filterItem.id} className="flex mb-4">
<div className="flex flex-col w-full mr-3">
<div className=" text-gray-500 font-bold">Filter</div>
<Field
className={controlClasses}
name='selectedField'
id='selectedField'
component='select'
value={filterItem?.fields?.selectedField || ''}
onChange={handleChange(filterItem.id)}
>
{filters.map((selectOption) => (
<option
key={selectOption.title}
value={`${selectOption.title}`}
>
{selectOption.label}
</option>
))}
</Field>
</div>
{filters.find((filter) =>
filter.title === filterItem?.fields?.selectedField
)?.type === 'enum' ? (
<div className="flex flex-col w-full mr-3">
<div className="text-gray-500 font-bold">
Value
</div>
<Field
className={controlClasses}
name="filterValue"
id='filterValue'
component="select"
value={filterItem?.fields?.filterValue || ''}
onChange={handleChange(filterItem.id)}
>
<option value="">Select Value</option>
{filters.find((filter) =>
filter.title === filterItem?.fields?.selectedField
)?.options?.map((option) => (
<option key={option} value={option}>
{option}
</option>
))}
</Field>
</div>
) : filters.find((filter) =>
filter.title === filterItem?.fields?.selectedField
)?.number ? (
<div className="flex flex-row w-full mr-3">
<div className="flex flex-col w-full mr-3">
<div className=" text-gray-500 font-bold">From</div>
<Field
className={controlClasses}
name='filterValueFrom'
placeholder='From'
id='filterValueFrom'
value={filterItem?.fields?.filterValueFrom || ''}
onChange={handleChange(filterItem.id)}
/>
</div>
<div className="flex flex-col w-full">
<div className=" text-gray-500 font-bold">To</div>
<Field
className={controlClasses}
name='filterValueTo'
placeholder='to'
id='filterValueTo'
value={filterItem?.fields?.filterValueTo || ''}
onChange={handleChange(filterItem.id)}
/>
</div>
</div>
) : filters.find(
(filter) =>
filter.title ===
filterItem?.fields?.selectedField
)?.date ? (
<div className='flex flex-row w-full mr-3'>
<div className='flex flex-col w-full mr-3'>
<div className=' text-gray-500 font-bold'>
From
</div>
<Field
className={controlClasses}
name='filterValueFrom'
placeholder='From'
id='filterValueFrom'
type='datetime-local'
value={filterItem?.fields?.filterValueFrom || ''}
onChange={handleChange(filterItem.id)}
/>
</div>
<div className='flex flex-col w-full'>
<div className=' text-gray-500 font-bold'>To</div>
<Field
className={controlClasses}
name='filterValueTo'
placeholder='to'
id='filterValueTo'
type='datetime-local'
value={filterItem?.fields?.filterValueTo || ''}
onChange={handleChange(filterItem.id)}
/>
</div>
</div>
) : (
<div className="flex flex-col w-full mr-3">
<div className=" text-gray-500 font-bold">Contains</div>
<Field
className={controlClasses}
name='filterValue'
placeholder='Contained'
id='filterValue'
value={filterItem?.fields?.filterValue || ''}
onChange={handleChange(filterItem.id)}
/>
</div>
)}
<div className="flex flex-col">
<div className=" text-gray-500 font-bold">Action</div>
<BaseButton
className="my-2"
type='reset'
color='danger'
label='Delete'
onClick={() => {
deleteFilter(filterItem.id)
}}
/>
</div>
</div>
)
})}
<div className="flex">
<BaseButton
className="my-2 mr-3"
color="success"
label='Apply'
onClick={handleSubmit}
/>
<BaseButton
className="my-2"
color='info'
label='Cancel'
onClick={handleReset}
/>
</div>
</>
</Form>
</Formik>
</CardBox> : null
}
<CardBoxModal
title="Please confirm"
buttonColor="info"
buttonLabel={loading ? 'Deleting...' : 'Confirm'}
isActive={isModalTrashActive}
onConfirm={handleDeleteAction}
onCancel={handleModalAction}
>
<p>Are you sure you want to delete this item?</p>
</CardBoxModal>
{dataGrid}
{selectedRows.length > 0 &&
createPortal(
<BaseButton
className='me-4'
color='danger'
label={`Delete ${selectedRows.length === 1 ? 'Row' : 'Rows'}`}
onClick={() => onDeleteRows(selectedRows)}
/>,
document.getElementById('delete-rows-button'),
)}
<ToastContainer />
</>
)
}
export default TableSampleAssets
export default TableAssets;

View File

@ -8,12 +8,12 @@ import {
GridValueGetterParams,
} from '@mui/x-data-grid';
import ImageField from '../ImageField';
import {saveFile} from "../../helpers/fileSaver";
import dataFormatter from '../../helpers/dataFormatter'
import DataGridMultiSelect from "../DataGridMultiSelect";
import { saveFile } from '../../helpers/fileSaver';
import dataFormatter from '../../helpers/dataFormatter';
import DataGridMultiSelect from '../DataGridMultiSelect';
import ListActionsPopover from '../ListActionsPopover';
import {hasPermission} from "../../helpers/userPermissions";
import { hasPermission } from '../../helpers/userPermissions';
type Params = (id: string) => void;
@ -21,11 +21,9 @@ export const loadColumns = async (
onDelete: Params,
entityName: string,
user
user,
) => {
async function callOptionsApi(entityName: string) {
if (!hasPermission(user, 'READ_' + entityName.toUpperCase())) return [];
try {
@ -37,10 +35,9 @@ export const loadColumns = async (
}
}
const hasUpdatePermission = hasPermission(user, 'UPDATE_ASSETS')
const hasUpdatePermission = hasPermission(user, 'UPDATE_ASSETS');
return [
{
field: 'project',
headerName: 'Project',
@ -50,7 +47,6 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
sortable: false,
@ -60,7 +56,6 @@ export const loadColumns = async (
valueOptions: await callOptionsApi('projects'),
valueGetter: (params: GridValueGetterParams) =>
params?.value?.id ?? params?.value,
},
{
@ -72,25 +67,31 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
},
{
field: 'asset_type',
headerName: 'Assettype',
headerName: 'Asset format',
flex: 1,
minWidth: 120,
filterable: false,
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
},
{
field: 'type',
headerName: 'Type',
flex: 1,
minWidth: 120,
filterable: false,
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
},
{
@ -102,10 +103,7 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
},
{
@ -117,10 +115,7 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
},
{
@ -132,10 +127,7 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
},
{
@ -147,11 +139,9 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
type: 'number',
},
{
@ -163,11 +153,9 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
type: 'number',
},
{
@ -179,11 +167,9 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
type: 'number',
},
{
@ -195,11 +181,9 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
type: 'number',
},
{
@ -211,10 +195,7 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
},
{
@ -226,11 +207,9 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
type: 'boolean',
},
{
@ -242,11 +221,9 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
type: 'boolean',
},
{
@ -258,13 +235,11 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
editable: hasUpdatePermission,
type: 'dateTime',
valueGetter: (params: GridValueGetterParams) =>
new Date(params.row.deleted_at_time),
},
{
@ -274,7 +249,6 @@ export const loadColumns = async (
headerClassName: 'datagrid--header',
cellClassName: 'datagrid--cell',
getActions: (params: GridRowParams) => {
return [
<div key={params?.row?.id}>
<ListActionsPopover
@ -282,12 +256,10 @@ export const loadColumns = async (
itemId={params?.row?.id}
pathEdit={`/assets/assets-edit/?id=${params?.row?.id}`}
pathView={`/assets/assets-view/?id=${params?.row?.id}`}
hasUpdatePermission={hasUpdatePermission}
/>
</div>,
]
];
},
},
];

View File

@ -1,28 +1,28 @@
import React from 'react'
import Link from 'next/link'
import { getButtonColor } from '../colors'
import BaseIcon from './BaseIcon'
import type { ColorButtonKey } from '../interfaces'
import React from 'react';
import Link from 'next/link';
import { getButtonColor } from '../colors';
import BaseIcon from './BaseIcon';
import type { ColorButtonKey } from '../interfaces';
import { useAppSelector } from '../stores/hooks';
type Props = {
label?: string
icon?: string
iconSize?: string | number
href?: string
target?: string
type?: string
color?: ColorButtonKey
className?: string
iconClassName?: string
asAnchor?: boolean
small?: boolean
outline?: boolean
active?: boolean
disabled?: boolean
roundedFull?: boolean
onClick?: (e: React.MouseEvent) => void
}
label?: string;
icon?: string;
iconSize?: string | number;
href?: string;
target?: string;
type?: string;
color?: ColorButtonKey;
className?: string;
iconClassName?: string;
asAnchor?: boolean;
small?: boolean;
outline?: boolean;
active?: boolean;
disabled?: boolean;
roundedFull?: boolean;
onClick?: (e: React.MouseEvent) => void;
};
export default function BaseButton({
label,
@ -57,40 +57,50 @@ export default function BaseButton({
roundedFull ? 'rounded-full' : `${corners}`,
getButtonColor(color, outline, !disabled, active),
className,
]
];
if (!label && icon) {
componentClass.push('p-1')
componentClass.push('p-1');
} else if (small) {
componentClass.push('text-sm', roundedFull ? 'px-3 py-1' : 'p-1')
componentClass.push('text-sm', roundedFull ? 'px-3 py-1' : 'p-1');
} else {
componentClass.push('py-2', roundedFull ? 'px-6' : 'px-3')
componentClass.push('py-2', roundedFull ? 'px-6' : 'px-3');
}
if (disabled) {
componentClass.push(outline ? 'opacity-50' : 'opacity-70')
componentClass.push(outline ? 'opacity-50' : 'opacity-70');
}
const componentClassString = componentClass.join(' ')
const componentClassString = componentClass.join(' ');
const componentChildren = (
<>
{icon && <BaseIcon path={icon} size={iconSize} className={iconClassName} />}
{label && <span className={small && icon ? 'px-1' : 'px-2'}>{label}</span>}
{icon && (
<BaseIcon path={icon} size={iconSize} className={iconClassName} />
)}
{label && (
<span className={small && icon ? 'px-1' : 'px-2'}>{label}</span>
)}
</>
)
);
if (href && !disabled) {
return (
<Link href={href} target={target} className={componentClassString}>
{componentChildren}
</Link>
)
);
}
return React.createElement(
asAnchor ? 'a' : 'button',
{ className: componentClassString, type: type ?? 'button', target, disabled, onClick },
componentChildren
)
{
className: componentClassString,
type: type ?? 'button',
target,
disabled,
onClick,
},
componentChildren,
);
}

View File

@ -1,14 +1,14 @@
import React from 'react'
import React from 'react';
import { useAppSelector } from '../stores/hooks';
type Props = {
navBar?: boolean
}
navBar?: boolean;
};
export default function BaseDivider({ navBar = false }: Props) {
const borders = useAppSelector((state) => state.style.borders);
const classAddon = navBar
? 'hidden lg:block lg:my-0.5 dark:border-dark-700'
: 'my-6 -mx-6 dark:border-dark-800'
: 'my-6 -mx-6 dark:border-dark-800';
return <hr className={`${classAddon} border-t ${borders} `} />
return <hr className={`${classAddon} border-t ${borders} `} />;
}

View File

@ -1,14 +1,14 @@
import React, { ReactNode } from 'react'
import React, { ReactNode } from 'react';
type Props = {
path: string
w?: string
h?: string
path: string;
w?: string;
h?: string;
fill?: string;
size?: string | number | null
className?: string
children?: ReactNode
}
size?: string | number | null;
className?: string;
children?: ReactNode;
};
export default function BaseIcon({
path,
@ -19,14 +19,21 @@ export default function BaseIcon({
className = '',
children,
}: Props) {
const iconSize = size ?? 16
const iconSize = size ?? 16;
return (
<span className={`inline-flex justify-center items-center ${w} ${h} ${className}`}>
<svg viewBox="0 0 24 24" width={iconSize} height={iconSize} className="inline-block">
<span
className={`inline-flex justify-center items-center ${w} ${h} ${className}`}
>
<svg
viewBox='0 0 24 24'
width={iconSize}
height={iconSize}
className='inline-block'
>
<path fill={fill || 'currentColor'} d={path} />
</svg>
{children}
</span>
)
);
}

Some files were not shown because too many files have changed in this diff Show More