Compare commits

...

1 Commits

Author SHA1 Message Date
Flatlogic Bot
dc86c7ef25 Updated via schema editor on 2026-03-23 10:42 2026-03-23 10:43:17 +00:00
9 changed files with 5935 additions and 7772 deletions

View File

@ -0,0 +1,36 @@
module.exports = {
/**
* @param {QueryInterface} queryInterface
* @param {Sequelize} Sequelize
* @returns {Promise<void>}
*/
async up(queryInterface, Sequelize) {
/**
* @type {Transaction}
*/
const transaction = await queryInterface.sequelize.transaction();
try {
await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
}
},
/**
* @param {QueryInterface} queryInterface
* @param {Sequelize} Sequelize
* @returns {Promise<void>}
*/
async down(queryInterface, Sequelize) {
/**
* @type {Transaction}
*/
const transaction = await queryInterface.sequelize.transaction();
try {
await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
}
},
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,3 @@
const express = require('express'); const express = require('express');
const cors = require('cors'); const cors = require('cors');
const app = express(); const app = express();
@ -14,15 +13,10 @@ const swaggerJsDoc = require('swagger-jsdoc');
const authRoutes = require('./routes/auth'); const authRoutes = require('./routes/auth');
const fileRoutes = require('./routes/file'); const fileRoutes = require('./routes/file');
const searchRoutes = require('./routes/search'); const searchRoutes = require('./routes/search');
const sqlRoutes = require('./routes/sql');
const pexelsRoutes = require('./routes/pexels'); const pexelsRoutes = require('./routes/pexels');
const openaiRoutes = require('./routes/openai'); const openaiRoutes = require('./routes/openai');
const usersRoutes = require('./routes/users');
const rolesRoutes = require('./routes/roles'); const rolesRoutes = require('./routes/roles');
const permissionsRoutes = require('./routes/permissions'); const permissionsRoutes = require('./routes/permissions');
@ -59,6 +53,7 @@ const pricing_plansRoutes = require('./routes/pricing_plans');
const plan_featuresRoutes = require('./routes/plan_features'); const plan_featuresRoutes = require('./routes/plan_features');
const usersRoutes = require('./routes/users');
const getBaseUrl = (url) => { const getBaseUrl = (url) => {
if (!url) return ''; if (!url) return '';
@ -67,17 +62,18 @@ const getBaseUrl = (url) => {
const options = { const options = {
definition: { definition: {
openapi: "3.0.0", openapi: '3.0.0',
info: { info: {
version: "1.0.0", version: '1.0.0',
title: "Course LMS", title: 'Course LMS',
description: "Course LMS Online REST API for Testing and Prototyping application. You can perform all major operations with your entities - create, delete and etc.", description:
}, 'Course LMS Online REST API for Testing and Prototyping application. You can perform all major operations with your entities - create, delete and etc.',
},
servers: [ servers: [
{ {
url: getBaseUrl(process.env.NEXT_PUBLIC_BACK_API) || config.swaggerUrl, url: getBaseUrl(process.env.NEXT_PUBLIC_BACK_API) || config.swaggerUrl,
description: "Development server", description: 'Development server',
} },
], ],
components: { components: {
securitySchemes: { securitySchemes: {
@ -85,28 +81,36 @@ const options = {
type: 'http', type: 'http',
scheme: 'bearer', scheme: 'bearer',
bearerFormat: 'JWT', bearerFormat: 'JWT',
} },
}, },
responses: { responses: {
UnauthorizedError: { UnauthorizedError: {
description: "Access token is missing or invalid" description: 'Access token is missing or invalid',
} },
} },
}, },
security: [{ security: [
bearerAuth: [] {
}] bearerAuth: [],
},
],
}, },
apis: ["./src/routes/*.js"], apis: ['./src/routes/*.js'],
}; };
const specs = swaggerJsDoc(options); const specs = swaggerJsDoc(options);
app.use('/api-docs', function (req, res, next) { app.use(
swaggerUI.host = getBaseUrl(process.env.NEXT_PUBLIC_BACK_API) || req.get('host'); '/api-docs',
next() function (req, res, next) {
}, swaggerUI.serve, swaggerUI.setup(specs)) swaggerUI.host =
getBaseUrl(process.env.NEXT_PUBLIC_BACK_API) || req.get('host');
next();
},
swaggerUI.serve,
swaggerUI.setup(specs),
);
app.use(cors({origin: true})); app.use(cors({ origin: true }));
require('./auth/auth'); require('./auth/auth');
app.use(bodyParser.json()); app.use(bodyParser.json());
@ -116,85 +120,148 @@ app.use('/api/file', fileRoutes);
app.use('/api/pexels', pexelsRoutes); app.use('/api/pexels', pexelsRoutes);
app.enable('trust proxy'); app.enable('trust proxy');
app.use('/api/users', passport.authenticate('jwt', {session: false}), usersRoutes);
app.use('/api/roles', passport.authenticate('jwt', {session: false}), rolesRoutes);
app.use('/api/permissions', passport.authenticate('jwt', {session: false}), permissionsRoutes);
app.use('/api/courses', passport.authenticate('jwt', {session: false}), coursesRoutes);
app.use('/api/course_sections', passport.authenticate('jwt', {session: false}), course_sectionsRoutes);
app.use('/api/lessons', passport.authenticate('jwt', {session: false}), lessonsRoutes);
app.use('/api/enrollments', passport.authenticate('jwt', {session: false}), enrollmentsRoutes);
app.use('/api/lesson_progress', passport.authenticate('jwt', {session: false}), lesson_progressRoutes);
app.use('/api/course_reviews', passport.authenticate('jwt', {session: false}), course_reviewsRoutes);
app.use('/api/course_announcements', passport.authenticate('jwt', {session: false}), course_announcementsRoutes);
app.use('/api/quizzes', passport.authenticate('jwt', {session: false}), quizzesRoutes);
app.use('/api/quiz_questions', passport.authenticate('jwt', {session: false}), quiz_questionsRoutes);
app.use('/api/quiz_options', passport.authenticate('jwt', {session: false}), quiz_optionsRoutes);
app.use('/api/quiz_attempts', passport.authenticate('jwt', {session: false}), quiz_attemptsRoutes);
app.use('/api/assignment_submissions', passport.authenticate('jwt', {session: false}), assignment_submissionsRoutes);
app.use('/api/marketing_pages', passport.authenticate('jwt', {session: false}), marketing_pagesRoutes);
app.use('/api/contact_messages', passport.authenticate('jwt', {session: false}), contact_messagesRoutes);
app.use('/api/pricing_plans', passport.authenticate('jwt', {session: false}), pricing_plansRoutes);
app.use('/api/plan_features', passport.authenticate('jwt', {session: false}), plan_featuresRoutes);
app.use( app.use(
'/api/openai', '/api/roles',
passport.authenticate('jwt', { session: false }), passport.authenticate('jwt', { session: false }),
openaiRoutes, rolesRoutes,
); );
app.use( app.use(
'/api/ai', '/api/permissions',
passport.authenticate('jwt', { session: false }), passport.authenticate('jwt', { session: false }),
openaiRoutes, permissionsRoutes,
);
app.use(
'/api/courses',
passport.authenticate('jwt', { session: false }),
coursesRoutes,
);
app.use(
'/api/course_sections',
passport.authenticate('jwt', { session: false }),
course_sectionsRoutes,
);
app.use(
'/api/lessons',
passport.authenticate('jwt', { session: false }),
lessonsRoutes,
);
app.use(
'/api/enrollments',
passport.authenticate('jwt', { session: false }),
enrollmentsRoutes,
);
app.use(
'/api/lesson_progress',
passport.authenticate('jwt', { session: false }),
lesson_progressRoutes,
);
app.use(
'/api/course_reviews',
passport.authenticate('jwt', { session: false }),
course_reviewsRoutes,
);
app.use(
'/api/course_announcements',
passport.authenticate('jwt', { session: false }),
course_announcementsRoutes,
);
app.use(
'/api/quizzes',
passport.authenticate('jwt', { session: false }),
quizzesRoutes,
);
app.use(
'/api/quiz_questions',
passport.authenticate('jwt', { session: false }),
quiz_questionsRoutes,
);
app.use(
'/api/quiz_options',
passport.authenticate('jwt', { session: false }),
quiz_optionsRoutes,
);
app.use(
'/api/quiz_attempts',
passport.authenticate('jwt', { session: false }),
quiz_attemptsRoutes,
);
app.use(
'/api/assignment_submissions',
passport.authenticate('jwt', { session: false }),
assignment_submissionsRoutes,
);
app.use(
'/api/marketing_pages',
passport.authenticate('jwt', { session: false }),
marketing_pagesRoutes,
);
app.use(
'/api/contact_messages',
passport.authenticate('jwt', { session: false }),
contact_messagesRoutes,
);
app.use(
'/api/pricing_plans',
passport.authenticate('jwt', { session: false }),
pricing_plansRoutes,
);
app.use(
'/api/plan_features',
passport.authenticate('jwt', { session: false }),
plan_featuresRoutes,
);
app.use(
'/api/users',
passport.authenticate('jwt', { session: false }),
usersRoutes,
);
app.use(
'/api/openai',
passport.authenticate('jwt', { session: false }),
openaiRoutes,
); );
app.use( app.use(
'/api/search', '/api/search',
passport.authenticate('jwt', { session: false }), passport.authenticate('jwt', { session: false }),
searchRoutes); searchRoutes,
app.use(
'/api/sql',
passport.authenticate('jwt', { session: false }),
sqlRoutes);
const publicDir = path.join(
__dirname,
'../public',
); );
const publicDir = path.join(__dirname, '../public');
if (fs.existsSync(publicDir)) { if (fs.existsSync(publicDir)) {
app.use('/', express.static(publicDir)); app.use('/', express.static(publicDir));
app.get('*', function(request, response) { app.get('*', function (request, response) {
response.sendFile( response.sendFile(path.resolve(publicDir, 'index.html'));
path.resolve(publicDir, 'index.html'),
);
}); });
} }
const PORT = process.env.NODE_ENV === 'dev_stage' ? 3000 : 8080; const PORT = process.env.NODE_ENV === 'dev_stage' ? 3000 : 8080;
db.sequelize.sync().then(function () {
app.listen(PORT, () => { app.listen(PORT, () => {
console.log(`Listening on port ${PORT}`); console.log(`Listening on port ${PORT}`);
}); });
});
module.exports = app; module.exports = app;

View File

@ -9,7 +9,6 @@ const Op = Sequelize.Op;
* @param {object} currentUser * @param {object} currentUser
*/ */
async function checkPermissions(permission, currentUser) { async function checkPermissions(permission, currentUser) {
if (!currentUser) { if (!currentUser) {
throw new ValidationError('auth.unauthorized'); throw new ValidationError('auth.unauthorized');
} }
@ -36,401 +35,88 @@ async function checkPermissions(permission, currentUser) {
} }
module.exports = class SearchService { module.exports = class SearchService {
static async search(searchQuery, currentUser ) { static async search(searchQuery, currentUser) {
try { try {
if (!searchQuery) { if (!searchQuery) {
throw new ValidationError('iam.errors.searchQueryRequired'); throw new ValidationError('iam.errors.searchQueryRequired');
} }
const tableColumns = { const tableColumns = {
courses: [
'title',
'slug',
"users": [
"firstName",
"lastName",
"phoneNumber",
"email",
],
'short_description',
"courses": [
"title",
"slug",
"short_description",
"description",
"currency",
],
'description',
"course_sections": [
"title",
],
'currency',
"lessons": [ ],
"title",
"slug",
"content",
"video_url",
],
course_sections: ['title'],
"enrollments": [
"notes",
],
lessons: ['title', 'slug', 'content', 'video_url'],
enrollments: ['notes'],
"course_reviews": [
"title",
"comment",
],
course_reviews: ['title', 'comment'],
"course_announcements": [
"title",
"message",
],
course_announcements: ['title', 'message'],
"quizzes": [
"title",
"instructions",
],
quizzes: ['title', 'instructions'],
"quiz_questions": [
"prompt",
"explanation",
],
quiz_questions: ['prompt', 'explanation'],
"quiz_options": [
"label",
],
quiz_options: ['label'],
assignment_submissions: ['submission_text', 'instructor_feedback'],
"assignment_submissions": [
"submission_text",
"instructor_feedback",
],
marketing_pages: [
"marketing_pages": [ 'title',
"title",
"slug",
"hero_headline",
"hero_subheadline",
"content",
],
'slug',
"contact_messages": [
"name",
"email",
"subject",
"message",
],
'hero_headline',
"pricing_plans": [
"name",
"description",
"currency",
],
'hero_subheadline',
"plan_features": [
'content',
"name", ],
"description", contact_messages: ['name', 'email', 'subject', 'message'],
], pricing_plans: ['name', 'description', 'currency'],
plan_features: ['name', 'description'],
users: ['firstName', 'lastName', 'phoneNumber', 'email'],
}; };
const columnsInt = { const columnsInt = {
courses: ['price'],
course_sections: ['position'],
lessons: ['duration_minutes', 'position'],
enrollments: ['progress_percent'],
lesson_progress: ['progress_percent'],
"courses": [ course_reviews: ['rating'],
"price", quizzes: ['time_limit_minutes', 'pass_percent'],
], quiz_questions: ['points', 'position'],
quiz_options: ['position'],
quiz_attempts: ['score_percent'],
"course_sections": [ assignment_submissions: ['grade_percent'],
"position", pricing_plans: ['price_monthly', 'price_yearly', 'sort_order'],
], plan_features: ['sort_order'],
"lessons": [
"duration_minutes",
"position",
],
"enrollments": [
"progress_percent",
],
"lesson_progress": [
"progress_percent",
],
"course_reviews": [
"rating",
],
"quizzes": [
"time_limit_minutes",
"pass_percent",
],
"quiz_questions": [
"points",
"position",
],
"quiz_options": [
"position",
],
"quiz_attempts": [
"score_percent",
],
"assignment_submissions": [
"grade_percent",
],
"pricing_plans": [
"price_monthly",
"price_yearly",
"sort_order",
],
"plan_features": [
"sort_order",
],
}; };
let allFoundRecords = []; let allFoundRecords = [];
@ -441,48 +127,63 @@ module.exports = class SearchService {
const attributesIntToSearch = columnsInt[tableName] || []; const attributesIntToSearch = columnsInt[tableName] || [];
const whereCondition = { const whereCondition = {
[Op.or]: [ [Op.or]: [
...attributesToSearch.map(attribute => ({ ...attributesToSearch.map((attribute) => ({
[attribute]: { [attribute]: {
[Op.iLike] : `%${searchQuery}%`, [Op.iLike]: `%${searchQuery}%`,
}, },
})), })),
...attributesIntToSearch.map(attribute => ( ...attributesIntToSearch.map((attribute) =>
Sequelize.where( Sequelize.where(
Sequelize.cast(Sequelize.col(`${tableName}.${attribute}`), 'varchar'), Sequelize.cast(
{ [Op.iLike]: `%${searchQuery}%` } Sequelize.col(`${tableName}.${attribute}`),
) 'varchar',
)), ),
{ [Op.iLike]: `%${searchQuery}%` },
),
),
], ],
}; };
const hasPermission = await checkPermissions(
`READ_${tableName.toUpperCase()}`,
const hasPermission = await checkPermissions(`READ_${tableName.toUpperCase()}`, currentUser); currentUser,
);
if (!hasPermission) { if (!hasPermission) {
continue; continue;
} }
const foundRecords = await db[tableName].findAll({ const foundRecords = await db[tableName].findAll({
where: whereCondition, where: whereCondition,
attributes: [...tableColumns[tableName], 'id', ...attributesIntToSearch], attributes: [
...tableColumns[tableName],
'id',
...attributesIntToSearch,
],
}); });
const modifiedRecords = foundRecords.map((record) => { const modifiedRecords = foundRecords.map((record) => {
const matchAttribute = []; const matchAttribute = [];
for (const attribute of attributesToSearch) { for (const attribute of attributesToSearch) {
if (record[attribute]?.toLowerCase()?.includes(searchQuery.toLowerCase())) { if (
record[attribute]
?.toLowerCase()
?.includes(searchQuery.toLowerCase())
) {
matchAttribute.push(attribute); matchAttribute.push(attribute);
} }
} }
for (const attribute of attributesIntToSearch) { for (const attribute of attributesIntToSearch) {
const castedValue = String(record[attribute]); const castedValue = String(record[attribute]);
if (castedValue && castedValue.toLowerCase().includes(searchQuery.toLowerCase())) { if (
castedValue &&
castedValue.toLowerCase().includes(searchQuery.toLowerCase())
) {
matchAttribute.push(attribute); matchAttribute.push(attribute);
} }
} }
return { return {
...record.get(), ...record.get(),
matchAttribute, matchAttribute,
@ -499,4 +200,4 @@ module.exports = class SearchService {
throw error; throw error;
} }
} }
} };

View File

@ -2,269 +2,230 @@ import dayjs from 'dayjs';
import _ from 'lodash'; import _ from 'lodash';
export default { export default {
filesFormatter(arr) { filesFormatter(arr) {
if (!arr || !arr.length) return []; if (!arr || !arr.length) return [];
return arr.map((item) => item); return arr.map((item) => item);
}, },
imageFormatter(arr) { imageFormatter(arr) {
if (!arr || !arr.length) return [] if (!arr || !arr.length) return [];
return arr.map(item => ({ return arr.map((item) => ({
publicUrl: item.publicUrl || '' publicUrl: item.publicUrl || '',
})) }));
}, },
oneImageFormatter(arr) { oneImageFormatter(arr) {
if (!arr || !arr.length) return '' if (!arr || !arr.length) return '';
return arr[0].publicUrl || '' return arr[0].publicUrl || '';
}, },
dateFormatter(date) { dateFormatter(date) {
if (!date) return '' if (!date) return '';
return dayjs(date).format('YYYY-MM-DD') return dayjs(date).format('YYYY-MM-DD');
}, },
dateTimeFormatter(date) { dateTimeFormatter(date) {
if (!date) return '' if (!date) return '';
return dayjs(date).format('YYYY-MM-DD HH:mm') return dayjs(date).format('YYYY-MM-DD HH:mm');
}, },
booleanFormatter(val) { booleanFormatter(val) {
return val ? 'Yes' : 'No' return val ? 'Yes' : 'No';
}, },
dataGridEditFormatter(obj) { dataGridEditFormatter(obj) {
return _.transform(obj, (result, value, key) => { return _.transform(obj, (result, value, key) => {
if (_.isArray(value)) { if (_.isArray(value)) {
result[key] = _.map(value, 'id'); result[key] = _.map(value, 'id');
} else if (_.isObject(value)) { } else if (_.isObject(value)) {
result[key] = value.id; result[key] = value.id;
} else { } else {
result[key] = value; result[key] = value;
} }
}); });
}, },
rolesManyListFormatter(val) {
usersManyListFormatter(val) { if (!val || !val.length) return [];
if (!val || !val.length) return [] return val.map((item) => item.name);
return val.map((item) => item.firstName) },
}, rolesOneListFormatter(val) {
usersOneListFormatter(val) { if (!val) return '';
if (!val) return '' return val.name;
return val.firstName },
}, rolesManyListFormatterEdit(val) {
usersManyListFormatterEdit(val) { if (!val || !val.length) return [];
if (!val || !val.length) return [] return val.map((item) => {
return val.map((item) => { return { id: item.id, label: item.name };
return {id: item.id, label: item.firstName} });
}); },
}, rolesOneListFormatterEdit(val) {
usersOneListFormatterEdit(val) { if (!val) return '';
if (!val) return '' return { label: val.name, id: val.id };
return {label: val.firstName, id: val.id} },
},
permissionsManyListFormatter(val) {
if (!val || !val.length) return [];
return val.map((item) => item.name);
rolesManyListFormatter(val) { },
if (!val || !val.length) return [] permissionsOneListFormatter(val) {
return val.map((item) => item.name) if (!val) return '';
}, return val.name;
rolesOneListFormatter(val) { },
if (!val) return '' permissionsManyListFormatterEdit(val) {
return val.name if (!val || !val.length) return [];
}, return val.map((item) => {
rolesManyListFormatterEdit(val) { return { id: item.id, label: item.name };
if (!val || !val.length) return [] });
return val.map((item) => { },
return {id: item.id, label: item.name} permissionsOneListFormatterEdit(val) {
}); if (!val) return '';
}, return { label: val.name, id: val.id };
rolesOneListFormatterEdit(val) { },
if (!val) return ''
return {label: val.name, id: val.id} coursesManyListFormatter(val) {
}, if (!val || !val.length) return [];
return val.map((item) => item.title);
},
coursesOneListFormatter(val) {
permissionsManyListFormatter(val) { if (!val) return '';
if (!val || !val.length) return [] return val.title;
return val.map((item) => item.name) },
}, coursesManyListFormatterEdit(val) {
permissionsOneListFormatter(val) { if (!val || !val.length) return [];
if (!val) return '' return val.map((item) => {
return val.name return { id: item.id, label: item.title };
}, });
permissionsManyListFormatterEdit(val) { },
if (!val || !val.length) return [] coursesOneListFormatterEdit(val) {
return val.map((item) => { if (!val) return '';
return {id: item.id, label: item.name} return { label: val.title, id: val.id };
}); },
},
permissionsOneListFormatterEdit(val) { course_sectionsManyListFormatter(val) {
if (!val) return '' if (!val || !val.length) return [];
return {label: val.name, id: val.id} return val.map((item) => item.title);
}, },
course_sectionsOneListFormatter(val) {
if (!val) return '';
return val.title;
coursesManyListFormatter(val) { },
if (!val || !val.length) return [] course_sectionsManyListFormatterEdit(val) {
return val.map((item) => item.title) if (!val || !val.length) return [];
}, return val.map((item) => {
coursesOneListFormatter(val) { return { id: item.id, label: item.title };
if (!val) return '' });
return val.title },
}, course_sectionsOneListFormatterEdit(val) {
coursesManyListFormatterEdit(val) { if (!val) return '';
if (!val || !val.length) return [] return { label: val.title, id: val.id };
return val.map((item) => { },
return {id: item.id, label: item.title}
}); lessonsManyListFormatter(val) {
}, if (!val || !val.length) return [];
coursesOneListFormatterEdit(val) { return val.map((item) => item.title);
if (!val) return '' },
return {label: val.title, id: val.id} lessonsOneListFormatter(val) {
}, if (!val) return '';
return val.title;
},
lessonsManyListFormatterEdit(val) {
course_sectionsManyListFormatter(val) { if (!val || !val.length) return [];
if (!val || !val.length) return [] return val.map((item) => {
return val.map((item) => item.title) return { id: item.id, label: item.title };
}, });
course_sectionsOneListFormatter(val) { },
if (!val) return '' lessonsOneListFormatterEdit(val) {
return val.title if (!val) return '';
}, return { label: val.title, id: val.id };
course_sectionsManyListFormatterEdit(val) { },
if (!val || !val.length) return []
return val.map((item) => { enrollmentsManyListFormatter(val) {
return {id: item.id, label: item.title} if (!val || !val.length) return [];
}); return val.map((item) => item.notes);
}, },
course_sectionsOneListFormatterEdit(val) { enrollmentsOneListFormatter(val) {
if (!val) return '' if (!val) return '';
return {label: val.title, id: val.id} return val.notes;
}, },
enrollmentsManyListFormatterEdit(val) {
if (!val || !val.length) return [];
return val.map((item) => {
lessonsManyListFormatter(val) { return { id: item.id, label: item.notes };
if (!val || !val.length) return [] });
return val.map((item) => item.title) },
}, enrollmentsOneListFormatterEdit(val) {
lessonsOneListFormatter(val) { if (!val) return '';
if (!val) return '' return { label: val.notes, id: val.id };
return val.title },
},
lessonsManyListFormatterEdit(val) { quizzesManyListFormatter(val) {
if (!val || !val.length) return [] if (!val || !val.length) return [];
return val.map((item) => { return val.map((item) => item.title);
return {id: item.id, label: item.title} },
}); quizzesOneListFormatter(val) {
}, if (!val) return '';
lessonsOneListFormatterEdit(val) { return val.title;
if (!val) return '' },
return {label: val.title, id: val.id} quizzesManyListFormatterEdit(val) {
}, if (!val || !val.length) return [];
return val.map((item) => {
return { id: item.id, label: item.title };
});
enrollmentsManyListFormatter(val) { },
if (!val || !val.length) return [] quizzesOneListFormatterEdit(val) {
return val.map((item) => item.notes) if (!val) return '';
}, return { label: val.title, id: val.id };
enrollmentsOneListFormatter(val) { },
if (!val) return ''
return val.notes quiz_questionsManyListFormatter(val) {
}, if (!val || !val.length) return [];
enrollmentsManyListFormatterEdit(val) { return val.map((item) => item.prompt);
if (!val || !val.length) return [] },
return val.map((item) => { quiz_questionsOneListFormatter(val) {
return {id: item.id, label: item.notes} if (!val) return '';
}); return val.prompt;
}, },
enrollmentsOneListFormatterEdit(val) { quiz_questionsManyListFormatterEdit(val) {
if (!val) return '' if (!val || !val.length) return [];
return {label: val.notes, id: val.id} return val.map((item) => {
}, return { id: item.id, label: item.prompt };
});
},
quiz_questionsOneListFormatterEdit(val) {
if (!val) return '';
return { label: val.prompt, id: val.id };
},
plan_featuresManyListFormatter(val) {
if (!val || !val.length) return [];
quizzesManyListFormatter(val) { return val.map((item) => item.name);
if (!val || !val.length) return [] },
return val.map((item) => item.title) plan_featuresOneListFormatter(val) {
}, if (!val) return '';
quizzesOneListFormatter(val) { return val.name;
if (!val) return '' },
return val.title plan_featuresManyListFormatterEdit(val) {
}, if (!val || !val.length) return [];
quizzesManyListFormatterEdit(val) { return val.map((item) => {
if (!val || !val.length) return [] return { id: item.id, label: item.name };
return val.map((item) => { });
return {id: item.id, label: item.title} },
}); plan_featuresOneListFormatterEdit(val) {
}, if (!val) return '';
quizzesOneListFormatterEdit(val) { return { label: val.name, id: val.id };
if (!val) return '' },
return {label: val.title, id: val.id}
}, usersManyListFormatter(val) {
if (!val || !val.length) return [];
return val.map((item) => item.firstName);
},
quiz_questionsManyListFormatter(val) { usersOneListFormatter(val) {
if (!val || !val.length) return [] if (!val) return '';
return val.map((item) => item.prompt) return val.firstName;
}, },
quiz_questionsOneListFormatter(val) { usersManyListFormatterEdit(val) {
if (!val) return '' if (!val || !val.length) return [];
return val.prompt return val.map((item) => {
}, return { id: item.id, label: item.firstName };
quiz_questionsManyListFormatterEdit(val) { });
if (!val || !val.length) return [] },
return val.map((item) => { usersOneListFormatterEdit(val) {
return {id: item.id, label: item.prompt} if (!val) return '';
}); return { label: val.firstName, id: val.id };
}, },
quiz_questionsOneListFormatterEdit(val) { };
if (!val) return ''
return {label: val.prompt, id: val.id}
},
plan_featuresManyListFormatter(val) {
if (!val || !val.length) return []
return val.map((item) => item.name)
},
plan_featuresOneListFormatter(val) {
if (!val) return ''
return val.name
},
plan_featuresManyListFormatterEdit(val) {
if (!val || !val.length) return []
return val.map((item) => {
return {id: item.id, label: item.name}
});
},
plan_featuresOneListFormatterEdit(val) {
if (!val) return ''
return {label: val.name, id: val.id}
},
}

View File

@ -1,5 +1,5 @@
import * as icon from '@mdi/js'; import * as icon from '@mdi/js';
import { MenuAsideItem } from './interfaces' import { MenuAsideItem } from './interfaces';
const menuAside: MenuAsideItem[] = [ const menuAside: MenuAsideItem[] = [
{ {
@ -7,22 +7,14 @@ const menuAside: MenuAsideItem[] = [
icon: icon.mdiViewDashboardOutline, icon: icon.mdiViewDashboardOutline,
label: 'Dashboard', label: 'Dashboard',
}, },
{
href: '/users/users-list',
label: 'Users',
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
icon: icon.mdiAccountGroup ?? icon.mdiTable,
permissions: 'READ_USERS'
},
{ {
href: '/roles/roles-list', href: '/roles/roles-list',
label: 'Roles', label: 'Roles',
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
icon: icon.mdiShieldAccountVariantOutline ?? icon.mdiTable, icon: icon.mdiShieldAccountVariantOutline ?? icon.mdiTable,
permissions: 'READ_ROLES' permissions: 'READ_ROLES',
}, },
{ {
href: '/permissions/permissions-list', href: '/permissions/permissions-list',
@ -30,135 +22,191 @@ const menuAside: MenuAsideItem[] = [
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
icon: icon.mdiShieldAccountOutline ?? icon.mdiTable, icon: icon.mdiShieldAccountOutline ?? icon.mdiTable,
permissions: 'READ_PERMISSIONS' permissions: 'READ_PERMISSIONS',
}, },
{ {
href: '/courses/courses-list', href: '/courses/courses-list',
label: 'Courses', label: 'Courses',
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
icon: 'mdiSchool' in icon ? icon['mdiSchool' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, icon:
permissions: 'READ_COURSES' 'mdiSchool' in icon
? icon['mdiSchool' as keyof typeof icon]
: icon.mdiTable ?? icon.mdiTable,
permissions: 'READ_COURSES',
}, },
{ {
href: '/course_sections/course_sections-list', href: '/course_sections/course_sections-list',
label: 'Course sections', label: 'Course sections',
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
icon: 'mdiViewList' in icon ? icon['mdiViewList' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, icon:
permissions: 'READ_COURSE_SECTIONS' 'mdiViewList' in icon
? icon['mdiViewList' as keyof typeof icon]
: icon.mdiTable ?? icon.mdiTable,
permissions: 'READ_COURSE_SECTIONS',
}, },
{ {
href: '/lessons/lessons-list', href: '/lessons/lessons-list',
label: 'Lessons', label: 'Lessons',
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
icon: 'mdiPlayCircleOutline' in icon ? icon['mdiPlayCircleOutline' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, icon:
permissions: 'READ_LESSONS' 'mdiPlayCircleOutline' in icon
? icon['mdiPlayCircleOutline' as keyof typeof icon]
: icon.mdiTable ?? icon.mdiTable,
permissions: 'READ_LESSONS',
}, },
{ {
href: '/enrollments/enrollments-list', href: '/enrollments/enrollments-list',
label: 'Enrollments', label: 'Enrollments',
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
icon: 'mdiAccountSchool' in icon ? icon['mdiAccountSchool' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, icon:
permissions: 'READ_ENROLLMENTS' 'mdiAccountSchool' in icon
? icon['mdiAccountSchool' as keyof typeof icon]
: icon.mdiTable ?? icon.mdiTable,
permissions: 'READ_ENROLLMENTS',
}, },
{ {
href: '/lesson_progress/lesson_progress-list', href: '/lesson_progress/lesson_progress-list',
label: 'Lesson progress', label: 'Lesson progress',
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
icon: 'mdiProgressCheck' in icon ? icon['mdiProgressCheck' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, icon:
permissions: 'READ_LESSON_PROGRESS' 'mdiProgressCheck' in icon
? icon['mdiProgressCheck' as keyof typeof icon]
: icon.mdiTable ?? icon.mdiTable,
permissions: 'READ_LESSON_PROGRESS',
}, },
{ {
href: '/course_reviews/course_reviews-list', href: '/course_reviews/course_reviews-list',
label: 'Course reviews', label: 'Course reviews',
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
icon: 'mdiStarCircle' in icon ? icon['mdiStarCircle' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, icon:
permissions: 'READ_COURSE_REVIEWS' 'mdiStarCircle' in icon
? icon['mdiStarCircle' as keyof typeof icon]
: icon.mdiTable ?? icon.mdiTable,
permissions: 'READ_COURSE_REVIEWS',
}, },
{ {
href: '/course_announcements/course_announcements-list', href: '/course_announcements/course_announcements-list',
label: 'Course announcements', label: 'Course announcements',
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
icon: 'mdiBullhorn' in icon ? icon['mdiBullhorn' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, icon:
permissions: 'READ_COURSE_ANNOUNCEMENTS' 'mdiBullhorn' in icon
? icon['mdiBullhorn' as keyof typeof icon]
: icon.mdiTable ?? icon.mdiTable,
permissions: 'READ_COURSE_ANNOUNCEMENTS',
}, },
{ {
href: '/quizzes/quizzes-list', href: '/quizzes/quizzes-list',
label: 'Quizzes', label: 'Quizzes',
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
icon: 'mdiHelpCircleOutline' in icon ? icon['mdiHelpCircleOutline' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, icon:
permissions: 'READ_QUIZZES' 'mdiHelpCircleOutline' in icon
? icon['mdiHelpCircleOutline' as keyof typeof icon]
: icon.mdiTable ?? icon.mdiTable,
permissions: 'READ_QUIZZES',
}, },
{ {
href: '/quiz_questions/quiz_questions-list', href: '/quiz_questions/quiz_questions-list',
label: 'Quiz questions', label: 'Quiz questions',
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
icon: 'mdiOrderBoolAscendingVariant' in icon ? icon['mdiOrderBoolAscendingVariant' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, icon:
permissions: 'READ_QUIZ_QUESTIONS' 'mdiOrderBoolAscendingVariant' in icon
? icon['mdiOrderBoolAscendingVariant' as keyof typeof icon]
: icon.mdiTable ?? icon.mdiTable,
permissions: 'READ_QUIZ_QUESTIONS',
}, },
{ {
href: '/quiz_options/quiz_options-list', href: '/quiz_options/quiz_options-list',
label: 'Quiz options', label: 'Quiz options',
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
icon: 'mdiCheckboxMarkedCircleOutline' in icon ? icon['mdiCheckboxMarkedCircleOutline' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, icon:
permissions: 'READ_QUIZ_OPTIONS' 'mdiCheckboxMarkedCircleOutline' in icon
? icon['mdiCheckboxMarkedCircleOutline' as keyof typeof icon]
: icon.mdiTable ?? icon.mdiTable,
permissions: 'READ_QUIZ_OPTIONS',
}, },
{ {
href: '/quiz_attempts/quiz_attempts-list', href: '/quiz_attempts/quiz_attempts-list',
label: 'Quiz attempts', label: 'Quiz attempts',
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
icon: 'mdiClipboardTextOutline' in icon ? icon['mdiClipboardTextOutline' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, icon:
permissions: 'READ_QUIZ_ATTEMPTS' 'mdiClipboardTextOutline' in icon
? icon['mdiClipboardTextOutline' as keyof typeof icon]
: icon.mdiTable ?? icon.mdiTable,
permissions: 'READ_QUIZ_ATTEMPTS',
}, },
{ {
href: '/assignment_submissions/assignment_submissions-list', href: '/assignment_submissions/assignment_submissions-list',
label: 'Assignment submissions', label: 'Assignment submissions',
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
icon: 'mdiFileUploadOutline' in icon ? icon['mdiFileUploadOutline' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, icon:
permissions: 'READ_ASSIGNMENT_SUBMISSIONS' 'mdiFileUploadOutline' in icon
? icon['mdiFileUploadOutline' as keyof typeof icon]
: icon.mdiTable ?? icon.mdiTable,
permissions: 'READ_ASSIGNMENT_SUBMISSIONS',
}, },
{ {
href: '/marketing_pages/marketing_pages-list', href: '/marketing_pages/marketing_pages-list',
label: 'Marketing pages', label: 'Marketing pages',
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
icon: 'mdiWeb' in icon ? icon['mdiWeb' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, icon:
permissions: 'READ_MARKETING_PAGES' 'mdiWeb' in icon
? icon['mdiWeb' as keyof typeof icon]
: icon.mdiTable ?? icon.mdiTable,
permissions: 'READ_MARKETING_PAGES',
}, },
{ {
href: '/contact_messages/contact_messages-list', href: '/contact_messages/contact_messages-list',
label: 'Contact messages', label: 'Contact messages',
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
icon: 'mdiEmailOutline' in icon ? icon['mdiEmailOutline' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, icon:
permissions: 'READ_CONTACT_MESSAGES' 'mdiEmailOutline' in icon
? icon['mdiEmailOutline' as keyof typeof icon]
: icon.mdiTable ?? icon.mdiTable,
permissions: 'READ_CONTACT_MESSAGES',
}, },
{ {
href: '/pricing_plans/pricing_plans-list', href: '/pricing_plans/pricing_plans-list',
label: 'Pricing plans', label: 'Pricing plans',
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
icon: 'mdiCashMultiple' in icon ? icon['mdiCashMultiple' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, icon:
permissions: 'READ_PRICING_PLANS' 'mdiCashMultiple' in icon
? icon['mdiCashMultiple' as keyof typeof icon]
: icon.mdiTable ?? icon.mdiTable,
permissions: 'READ_PRICING_PLANS',
}, },
{ {
href: '/plan_features/plan_features-list', href: '/plan_features/plan_features-list',
label: 'Plan features', label: 'Plan features',
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
icon: 'mdiChecklist' in icon ? icon['mdiChecklist' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, icon:
permissions: 'READ_PLAN_FEATURES' 'mdiChecklist' in icon
? icon['mdiChecklist' as keyof typeof icon]
: icon.mdiTable ?? icon.mdiTable,
permissions: 'READ_PLAN_FEATURES',
},
{
href: '/users/users-list',
label: 'Users',
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
icon: icon.mdiAccountGroup ?? icon.mdiTable,
permissions: 'READ_USERS',
}, },
{ {
href: '/profile', href: '/profile',
@ -166,14 +214,13 @@ const menuAside: MenuAsideItem[] = [
icon: icon.mdiAccountCircle, icon: icon.mdiAccountCircle,
}, },
{ {
href: '/api-docs', href: '/api-docs',
target: '_blank', target: '_blank',
label: 'Swagger API', label: 'Swagger API',
icon: icon.mdiFileCode, icon: icon.mdiFileCode,
permissions: 'READ_API_DOCS' permissions: 'READ_API_DOCS',
}, },
] ];
export default menuAside export default menuAside;

File diff suppressed because it is too large Load Diff

View File

@ -4,25 +4,25 @@ import mainReducer from './mainSlice';
import authSlice from './authSlice'; import authSlice from './authSlice';
import openAiSlice from './openAiSlice'; import openAiSlice from './openAiSlice';
import usersSlice from "./users/usersSlice"; import rolesSlice from './roles/rolesSlice';
import rolesSlice from "./roles/rolesSlice"; import permissionsSlice from './permissions/permissionsSlice';
import permissionsSlice from "./permissions/permissionsSlice"; import coursesSlice from './courses/coursesSlice';
import coursesSlice from "./courses/coursesSlice"; import course_sectionsSlice from './course_sections/course_sectionsSlice';
import course_sectionsSlice from "./course_sections/course_sectionsSlice"; import lessonsSlice from './lessons/lessonsSlice';
import lessonsSlice from "./lessons/lessonsSlice"; import enrollmentsSlice from './enrollments/enrollmentsSlice';
import enrollmentsSlice from "./enrollments/enrollmentsSlice"; import lesson_progressSlice from './lesson_progress/lesson_progressSlice';
import lesson_progressSlice from "./lesson_progress/lesson_progressSlice"; import course_reviewsSlice from './course_reviews/course_reviewsSlice';
import course_reviewsSlice from "./course_reviews/course_reviewsSlice"; import course_announcementsSlice from './course_announcements/course_announcementsSlice';
import course_announcementsSlice from "./course_announcements/course_announcementsSlice"; import quizzesSlice from './quizzes/quizzesSlice';
import quizzesSlice from "./quizzes/quizzesSlice"; import quiz_questionsSlice from './quiz_questions/quiz_questionsSlice';
import quiz_questionsSlice from "./quiz_questions/quiz_questionsSlice"; import quiz_optionsSlice from './quiz_options/quiz_optionsSlice';
import quiz_optionsSlice from "./quiz_options/quiz_optionsSlice"; import quiz_attemptsSlice from './quiz_attempts/quiz_attemptsSlice';
import quiz_attemptsSlice from "./quiz_attempts/quiz_attemptsSlice"; import assignment_submissionsSlice from './assignment_submissions/assignment_submissionsSlice';
import assignment_submissionsSlice from "./assignment_submissions/assignment_submissionsSlice"; import marketing_pagesSlice from './marketing_pages/marketing_pagesSlice';
import marketing_pagesSlice from "./marketing_pages/marketing_pagesSlice"; import contact_messagesSlice from './contact_messages/contact_messagesSlice';
import contact_messagesSlice from "./contact_messages/contact_messagesSlice"; import pricing_plansSlice from './pricing_plans/pricing_plansSlice';
import pricing_plansSlice from "./pricing_plans/pricing_plansSlice"; import plan_featuresSlice from './plan_features/plan_featuresSlice';
import plan_featuresSlice from "./plan_features/plan_featuresSlice"; import usersSlice from './users/usersSlice';
export const store = configureStore({ export const store = configureStore({
reducer: { reducer: {
@ -31,29 +31,29 @@ export const store = configureStore({
auth: authSlice, auth: authSlice,
openAi: openAiSlice, openAi: openAiSlice,
users: usersSlice, roles: rolesSlice,
roles: rolesSlice, permissions: permissionsSlice,
permissions: permissionsSlice, courses: coursesSlice,
courses: coursesSlice, course_sections: course_sectionsSlice,
course_sections: course_sectionsSlice, lessons: lessonsSlice,
lessons: lessonsSlice, enrollments: enrollmentsSlice,
enrollments: enrollmentsSlice, lesson_progress: lesson_progressSlice,
lesson_progress: lesson_progressSlice, course_reviews: course_reviewsSlice,
course_reviews: course_reviewsSlice, course_announcements: course_announcementsSlice,
course_announcements: course_announcementsSlice, quizzes: quizzesSlice,
quizzes: quizzesSlice, quiz_questions: quiz_questionsSlice,
quiz_questions: quiz_questionsSlice, quiz_options: quiz_optionsSlice,
quiz_options: quiz_optionsSlice, quiz_attempts: quiz_attemptsSlice,
quiz_attempts: quiz_attemptsSlice, assignment_submissions: assignment_submissionsSlice,
assignment_submissions: assignment_submissionsSlice, marketing_pages: marketing_pagesSlice,
marketing_pages: marketing_pagesSlice, contact_messages: contact_messagesSlice,
contact_messages: contact_messagesSlice, pricing_plans: pricing_plansSlice,
pricing_plans: pricing_plansSlice, plan_features: plan_featuresSlice,
plan_features: plan_featuresSlice, users: usersSlice,
}, },
}) });
// Infer the `RootState` and `AppDispatch` types from the store itself // Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState> export type RootState = ReturnType<typeof store.getState>;
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState} // Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch export type AppDispatch = typeof store.dispatch;