Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc86c7ef25 |
36
backend/src/db/migrations/1774262568375.js
Normal file
36
backend/src/db/migrations/1774262568375.js
Normal 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
@ -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,26 +81,34 @@ 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: [{
|
|
||||||
bearerAuth: []
|
|
||||||
}]
|
|
||||||
},
|
},
|
||||||
apis: ["./src/routes/*.js"],
|
},
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
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');
|
||||||
@ -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/roles',
|
||||||
|
passport.authenticate('jwt', { session: false }),
|
||||||
|
rolesRoutes,
|
||||||
|
);
|
||||||
|
|
||||||
app.use('/api/users', passport.authenticate('jwt', {session: false}), usersRoutes);
|
app.use(
|
||||||
|
'/api/permissions',
|
||||||
|
passport.authenticate('jwt', { session: false }),
|
||||||
|
permissionsRoutes,
|
||||||
|
);
|
||||||
|
|
||||||
app.use('/api/roles', passport.authenticate('jwt', {session: false}), rolesRoutes);
|
app.use(
|
||||||
|
'/api/courses',
|
||||||
|
passport.authenticate('jwt', { session: false }),
|
||||||
|
coursesRoutes,
|
||||||
|
);
|
||||||
|
|
||||||
app.use('/api/permissions', passport.authenticate('jwt', {session: false}), permissionsRoutes);
|
app.use(
|
||||||
|
'/api/course_sections',
|
||||||
|
passport.authenticate('jwt', { session: false }),
|
||||||
|
course_sectionsRoutes,
|
||||||
|
);
|
||||||
|
|
||||||
app.use('/api/courses', passport.authenticate('jwt', {session: false}), coursesRoutes);
|
app.use(
|
||||||
|
'/api/lessons',
|
||||||
|
passport.authenticate('jwt', { session: false }),
|
||||||
|
lessonsRoutes,
|
||||||
|
);
|
||||||
|
|
||||||
app.use('/api/course_sections', passport.authenticate('jwt', {session: false}), course_sectionsRoutes);
|
app.use(
|
||||||
|
'/api/enrollments',
|
||||||
|
passport.authenticate('jwt', { session: false }),
|
||||||
|
enrollmentsRoutes,
|
||||||
|
);
|
||||||
|
|
||||||
app.use('/api/lessons', passport.authenticate('jwt', {session: false}), lessonsRoutes);
|
app.use(
|
||||||
|
'/api/lesson_progress',
|
||||||
|
passport.authenticate('jwt', { session: false }),
|
||||||
|
lesson_progressRoutes,
|
||||||
|
);
|
||||||
|
|
||||||
app.use('/api/enrollments', passport.authenticate('jwt', {session: false}), enrollmentsRoutes);
|
app.use(
|
||||||
|
'/api/course_reviews',
|
||||||
|
passport.authenticate('jwt', { session: false }),
|
||||||
|
course_reviewsRoutes,
|
||||||
|
);
|
||||||
|
|
||||||
app.use('/api/lesson_progress', passport.authenticate('jwt', {session: false}), lesson_progressRoutes);
|
app.use(
|
||||||
|
'/api/course_announcements',
|
||||||
|
passport.authenticate('jwt', { session: false }),
|
||||||
|
course_announcementsRoutes,
|
||||||
|
);
|
||||||
|
|
||||||
app.use('/api/course_reviews', passport.authenticate('jwt', {session: false}), course_reviewsRoutes);
|
app.use(
|
||||||
|
'/api/quizzes',
|
||||||
|
passport.authenticate('jwt', { session: false }),
|
||||||
|
quizzesRoutes,
|
||||||
|
);
|
||||||
|
|
||||||
app.use('/api/course_announcements', passport.authenticate('jwt', {session: false}), course_announcementsRoutes);
|
app.use(
|
||||||
|
'/api/quiz_questions',
|
||||||
|
passport.authenticate('jwt', { session: false }),
|
||||||
|
quiz_questionsRoutes,
|
||||||
|
);
|
||||||
|
|
||||||
app.use('/api/quizzes', passport.authenticate('jwt', {session: false}), quizzesRoutes);
|
app.use(
|
||||||
|
'/api/quiz_options',
|
||||||
|
passport.authenticate('jwt', { session: false }),
|
||||||
|
quiz_optionsRoutes,
|
||||||
|
);
|
||||||
|
|
||||||
app.use('/api/quiz_questions', passport.authenticate('jwt', {session: false}), quiz_questionsRoutes);
|
app.use(
|
||||||
|
'/api/quiz_attempts',
|
||||||
|
passport.authenticate('jwt', { session: false }),
|
||||||
|
quiz_attemptsRoutes,
|
||||||
|
);
|
||||||
|
|
||||||
app.use('/api/quiz_options', passport.authenticate('jwt', {session: false}), quiz_optionsRoutes);
|
app.use(
|
||||||
|
'/api/assignment_submissions',
|
||||||
|
passport.authenticate('jwt', { session: false }),
|
||||||
|
assignment_submissionsRoutes,
|
||||||
|
);
|
||||||
|
|
||||||
app.use('/api/quiz_attempts', passport.authenticate('jwt', {session: false}), quiz_attemptsRoutes);
|
app.use(
|
||||||
|
'/api/marketing_pages',
|
||||||
|
passport.authenticate('jwt', { session: false }),
|
||||||
|
marketing_pagesRoutes,
|
||||||
|
);
|
||||||
|
|
||||||
app.use('/api/assignment_submissions', passport.authenticate('jwt', {session: false}), assignment_submissionsRoutes);
|
app.use(
|
||||||
|
'/api/contact_messages',
|
||||||
|
passport.authenticate('jwt', { session: false }),
|
||||||
|
contact_messagesRoutes,
|
||||||
|
);
|
||||||
|
|
||||||
app.use('/api/marketing_pages', passport.authenticate('jwt', {session: false}), marketing_pagesRoutes);
|
app.use(
|
||||||
|
'/api/pricing_plans',
|
||||||
|
passport.authenticate('jwt', { session: false }),
|
||||||
|
pricing_plansRoutes,
|
||||||
|
);
|
||||||
|
|
||||||
app.use('/api/contact_messages', passport.authenticate('jwt', {session: false}), contact_messagesRoutes);
|
app.use(
|
||||||
|
'/api/plan_features',
|
||||||
|
passport.authenticate('jwt', { session: false }),
|
||||||
|
plan_featuresRoutes,
|
||||||
|
);
|
||||||
|
|
||||||
app.use('/api/pricing_plans', passport.authenticate('jwt', {session: false}), pricing_plansRoutes);
|
app.use(
|
||||||
|
'/api/users',
|
||||||
app.use('/api/plan_features', passport.authenticate('jwt', {session: false}), plan_featuresRoutes);
|
passport.authenticate('jwt', { session: false }),
|
||||||
|
usersRoutes,
|
||||||
|
);
|
||||||
|
|
||||||
app.use(
|
app.use(
|
||||||
'/api/openai',
|
'/api/openai',
|
||||||
passport.authenticate('jwt', { session: false }),
|
passport.authenticate('jwt', { session: false }),
|
||||||
openaiRoutes,
|
openaiRoutes,
|
||||||
);
|
);
|
||||||
app.use(
|
|
||||||
'/api/ai',
|
|
||||||
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;
|
||||||
|
|||||||
@ -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');
|
||||||
}
|
}
|
||||||
@ -42,395 +41,82 @@ module.exports = class SearchService {
|
|||||||
throw new ValidationError('iam.errors.searchQueryRequired');
|
throw new ValidationError('iam.errors.searchQueryRequired');
|
||||||
}
|
}
|
||||||
const tableColumns = {
|
const tableColumns = {
|
||||||
|
courses: [
|
||||||
|
'title',
|
||||||
|
|
||||||
|
'slug',
|
||||||
|
|
||||||
|
'short_description',
|
||||||
|
|
||||||
|
'description',
|
||||||
|
|
||||||
|
'currency',
|
||||||
"users": [
|
|
||||||
|
|
||||||
"firstName",
|
|
||||||
|
|
||||||
"lastName",
|
|
||||||
|
|
||||||
"phoneNumber",
|
|
||||||
|
|
||||||
"email",
|
|
||||||
|
|
||||||
],
|
],
|
||||||
|
|
||||||
|
course_sections: ['title'],
|
||||||
|
|
||||||
|
lessons: ['title', 'slug', 'content', 'video_url'],
|
||||||
|
|
||||||
|
enrollments: ['notes'],
|
||||||
|
|
||||||
|
course_reviews: ['title', 'comment'],
|
||||||
|
|
||||||
|
course_announcements: ['title', 'message'],
|
||||||
|
|
||||||
|
quizzes: ['title', 'instructions'],
|
||||||
|
|
||||||
|
quiz_questions: ['prompt', 'explanation'],
|
||||||
|
|
||||||
"courses": [
|
quiz_options: ['label'],
|
||||||
|
|
||||||
"title",
|
assignment_submissions: ['submission_text', 'instructor_feedback'],
|
||||||
|
|
||||||
"slug",
|
marketing_pages: [
|
||||||
|
'title',
|
||||||
|
|
||||||
"short_description",
|
'slug',
|
||||||
|
|
||||||
"description",
|
'hero_headline',
|
||||||
|
|
||||||
"currency",
|
'hero_subheadline',
|
||||||
|
|
||||||
|
'content',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
contact_messages: ['name', 'email', 'subject', 'message'],
|
||||||
|
|
||||||
|
pricing_plans: ['name', 'description', 'currency'],
|
||||||
|
|
||||||
|
plan_features: ['name', 'description'],
|
||||||
|
|
||||||
|
users: ['firstName', 'lastName', 'phoneNumber', 'email'],
|
||||||
|
|
||||||
"course_sections": [
|
|
||||||
|
|
||||||
"title",
|
|
||||||
|
|
||||||
],
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"lessons": [
|
|
||||||
|
|
||||||
"title",
|
|
||||||
|
|
||||||
"slug",
|
|
||||||
|
|
||||||
"content",
|
|
||||||
|
|
||||||
"video_url",
|
|
||||||
|
|
||||||
],
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"enrollments": [
|
|
||||||
|
|
||||||
"notes",
|
|
||||||
|
|
||||||
],
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"course_reviews": [
|
|
||||||
|
|
||||||
"title",
|
|
||||||
|
|
||||||
"comment",
|
|
||||||
|
|
||||||
],
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"course_announcements": [
|
|
||||||
|
|
||||||
"title",
|
|
||||||
|
|
||||||
"message",
|
|
||||||
|
|
||||||
],
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"quizzes": [
|
|
||||||
|
|
||||||
"title",
|
|
||||||
|
|
||||||
"instructions",
|
|
||||||
|
|
||||||
],
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"quiz_questions": [
|
|
||||||
|
|
||||||
"prompt",
|
|
||||||
|
|
||||||
"explanation",
|
|
||||||
|
|
||||||
],
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"quiz_options": [
|
|
||||||
|
|
||||||
"label",
|
|
||||||
|
|
||||||
],
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"assignment_submissions": [
|
|
||||||
|
|
||||||
"submission_text",
|
|
||||||
|
|
||||||
"instructor_feedback",
|
|
||||||
|
|
||||||
],
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"marketing_pages": [
|
|
||||||
|
|
||||||
"title",
|
|
||||||
|
|
||||||
"slug",
|
|
||||||
|
|
||||||
"hero_headline",
|
|
||||||
|
|
||||||
"hero_subheadline",
|
|
||||||
|
|
||||||
"content",
|
|
||||||
|
|
||||||
],
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"contact_messages": [
|
|
||||||
|
|
||||||
"name",
|
|
||||||
|
|
||||||
"email",
|
|
||||||
|
|
||||||
"subject",
|
|
||||||
|
|
||||||
"message",
|
|
||||||
|
|
||||||
],
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"pricing_plans": [
|
|
||||||
|
|
||||||
"name",
|
|
||||||
|
|
||||||
"description",
|
|
||||||
|
|
||||||
"currency",
|
|
||||||
|
|
||||||
],
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"plan_features": [
|
|
||||||
|
|
||||||
"name",
|
|
||||||
|
|
||||||
"description",
|
|
||||||
|
|
||||||
],
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
const columnsInt = {
|
const columnsInt = {
|
||||||
|
courses: ['price'],
|
||||||
|
|
||||||
|
course_sections: ['position'],
|
||||||
|
|
||||||
|
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'],
|
||||||
|
|
||||||
"courses": [
|
assignment_submissions: ['grade_percent'],
|
||||||
|
|
||||||
"price",
|
|
||||||
|
|
||||||
],
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"course_sections": [
|
|
||||||
|
|
||||||
"position",
|
|
||||||
|
|
||||||
],
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"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",
|
|
||||||
|
|
||||||
],
|
|
||||||
|
|
||||||
|
pricing_plans: ['price_monthly', 'price_yearly', 'sort_order'],
|
||||||
|
|
||||||
|
plan_features: ['sort_order'],
|
||||||
};
|
};
|
||||||
|
|
||||||
let allFoundRecords = [];
|
let allFoundRecords = [];
|
||||||
@ -441,44 +127,59 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -499,4 +200,4 @@ module.exports = class SearchService {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|||||||
@ -7,25 +7,25 @@ export default {
|
|||||||
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) => {
|
||||||
@ -39,232 +39,193 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
usersManyListFormatter(val) {
|
|
||||||
if (!val || !val.length) return []
|
|
||||||
return val.map((item) => item.firstName)
|
|
||||||
},
|
|
||||||
usersOneListFormatter(val) {
|
|
||||||
if (!val) return ''
|
|
||||||
return val.firstName
|
|
||||||
},
|
|
||||||
usersManyListFormatterEdit(val) {
|
|
||||||
if (!val || !val.length) return []
|
|
||||||
return val.map((item) => {
|
|
||||||
return {id: item.id, label: item.firstName}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
usersOneListFormatterEdit(val) {
|
|
||||||
if (!val) return ''
|
|
||||||
return {label: val.firstName, id: val.id}
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
rolesManyListFormatter(val) {
|
rolesManyListFormatter(val) {
|
||||||
if (!val || !val.length) return []
|
if (!val || !val.length) return [];
|
||||||
return val.map((item) => item.name)
|
return val.map((item) => item.name);
|
||||||
},
|
},
|
||||||
rolesOneListFormatter(val) {
|
rolesOneListFormatter(val) {
|
||||||
if (!val) return ''
|
if (!val) return '';
|
||||||
return val.name
|
return val.name;
|
||||||
},
|
},
|
||||||
rolesManyListFormatterEdit(val) {
|
rolesManyListFormatterEdit(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.name };
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
rolesOneListFormatterEdit(val) {
|
rolesOneListFormatterEdit(val) {
|
||||||
if (!val) return ''
|
if (!val) return '';
|
||||||
return {label: val.name, id: val.id}
|
return { label: val.name, id: val.id };
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
permissionsManyListFormatter(val) {
|
permissionsManyListFormatter(val) {
|
||||||
if (!val || !val.length) return []
|
if (!val || !val.length) return [];
|
||||||
return val.map((item) => item.name)
|
return val.map((item) => item.name);
|
||||||
},
|
},
|
||||||
permissionsOneListFormatter(val) {
|
permissionsOneListFormatter(val) {
|
||||||
if (!val) return ''
|
if (!val) return '';
|
||||||
return val.name
|
return val.name;
|
||||||
},
|
},
|
||||||
permissionsManyListFormatterEdit(val) {
|
permissionsManyListFormatterEdit(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.name };
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
permissionsOneListFormatterEdit(val) {
|
permissionsOneListFormatterEdit(val) {
|
||||||
if (!val) return ''
|
if (!val) return '';
|
||||||
return {label: val.name, id: val.id}
|
return { label: val.name, id: val.id };
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
coursesManyListFormatter(val) {
|
coursesManyListFormatter(val) {
|
||||||
if (!val || !val.length) return []
|
if (!val || !val.length) return [];
|
||||||
return val.map((item) => item.title)
|
return val.map((item) => item.title);
|
||||||
},
|
},
|
||||||
coursesOneListFormatter(val) {
|
coursesOneListFormatter(val) {
|
||||||
if (!val) return ''
|
if (!val) return '';
|
||||||
return val.title
|
return val.title;
|
||||||
},
|
},
|
||||||
coursesManyListFormatterEdit(val) {
|
coursesManyListFormatterEdit(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.title}
|
return { id: item.id, label: item.title };
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
coursesOneListFormatterEdit(val) {
|
coursesOneListFormatterEdit(val) {
|
||||||
if (!val) return ''
|
if (!val) return '';
|
||||||
return {label: val.title, id: val.id}
|
return { label: val.title, id: val.id };
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
course_sectionsManyListFormatter(val) {
|
course_sectionsManyListFormatter(val) {
|
||||||
if (!val || !val.length) return []
|
if (!val || !val.length) return [];
|
||||||
return val.map((item) => item.title)
|
return val.map((item) => item.title);
|
||||||
},
|
},
|
||||||
course_sectionsOneListFormatter(val) {
|
course_sectionsOneListFormatter(val) {
|
||||||
if (!val) return ''
|
if (!val) return '';
|
||||||
return val.title
|
return val.title;
|
||||||
},
|
},
|
||||||
course_sectionsManyListFormatterEdit(val) {
|
course_sectionsManyListFormatterEdit(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.title}
|
return { id: item.id, label: item.title };
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
course_sectionsOneListFormatterEdit(val) {
|
course_sectionsOneListFormatterEdit(val) {
|
||||||
if (!val) return ''
|
if (!val) return '';
|
||||||
return {label: val.title, id: val.id}
|
return { label: val.title, id: val.id };
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
lessonsManyListFormatter(val) {
|
lessonsManyListFormatter(val) {
|
||||||
if (!val || !val.length) return []
|
if (!val || !val.length) return [];
|
||||||
return val.map((item) => item.title)
|
return val.map((item) => item.title);
|
||||||
},
|
},
|
||||||
lessonsOneListFormatter(val) {
|
lessonsOneListFormatter(val) {
|
||||||
if (!val) return ''
|
if (!val) return '';
|
||||||
return val.title
|
return val.title;
|
||||||
},
|
},
|
||||||
lessonsManyListFormatterEdit(val) {
|
lessonsManyListFormatterEdit(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.title}
|
return { id: item.id, label: item.title };
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
lessonsOneListFormatterEdit(val) {
|
lessonsOneListFormatterEdit(val) {
|
||||||
if (!val) return ''
|
if (!val) return '';
|
||||||
return {label: val.title, id: val.id}
|
return { label: val.title, id: val.id };
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
enrollmentsManyListFormatter(val) {
|
enrollmentsManyListFormatter(val) {
|
||||||
if (!val || !val.length) return []
|
if (!val || !val.length) return [];
|
||||||
return val.map((item) => item.notes)
|
return val.map((item) => item.notes);
|
||||||
},
|
},
|
||||||
enrollmentsOneListFormatter(val) {
|
enrollmentsOneListFormatter(val) {
|
||||||
if (!val) return ''
|
if (!val) return '';
|
||||||
return val.notes
|
return val.notes;
|
||||||
},
|
},
|
||||||
enrollmentsManyListFormatterEdit(val) {
|
enrollmentsManyListFormatterEdit(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.notes}
|
return { id: item.id, label: item.notes };
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
enrollmentsOneListFormatterEdit(val) {
|
enrollmentsOneListFormatterEdit(val) {
|
||||||
if (!val) return ''
|
if (!val) return '';
|
||||||
return {label: val.notes, id: val.id}
|
return { label: val.notes, id: val.id };
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
quizzesManyListFormatter(val) {
|
quizzesManyListFormatter(val) {
|
||||||
if (!val || !val.length) return []
|
if (!val || !val.length) return [];
|
||||||
return val.map((item) => item.title)
|
return val.map((item) => item.title);
|
||||||
},
|
},
|
||||||
quizzesOneListFormatter(val) {
|
quizzesOneListFormatter(val) {
|
||||||
if (!val) return ''
|
if (!val) return '';
|
||||||
return val.title
|
return val.title;
|
||||||
},
|
},
|
||||||
quizzesManyListFormatterEdit(val) {
|
quizzesManyListFormatterEdit(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.title}
|
return { id: item.id, label: item.title };
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
quizzesOneListFormatterEdit(val) {
|
quizzesOneListFormatterEdit(val) {
|
||||||
if (!val) return ''
|
if (!val) return '';
|
||||||
return {label: val.title, id: val.id}
|
return { label: val.title, id: val.id };
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
quiz_questionsManyListFormatter(val) {
|
quiz_questionsManyListFormatter(val) {
|
||||||
if (!val || !val.length) return []
|
if (!val || !val.length) return [];
|
||||||
return val.map((item) => item.prompt)
|
return val.map((item) => item.prompt);
|
||||||
},
|
},
|
||||||
quiz_questionsOneListFormatter(val) {
|
quiz_questionsOneListFormatter(val) {
|
||||||
if (!val) return ''
|
if (!val) return '';
|
||||||
return val.prompt
|
return val.prompt;
|
||||||
},
|
},
|
||||||
quiz_questionsManyListFormatterEdit(val) {
|
quiz_questionsManyListFormatterEdit(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.prompt}
|
return { id: item.id, label: item.prompt };
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
quiz_questionsOneListFormatterEdit(val) {
|
quiz_questionsOneListFormatterEdit(val) {
|
||||||
if (!val) return ''
|
if (!val) return '';
|
||||||
return {label: val.prompt, id: val.id}
|
return { label: val.prompt, id: val.id };
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
plan_featuresManyListFormatter(val) {
|
plan_featuresManyListFormatter(val) {
|
||||||
if (!val || !val.length) return []
|
if (!val || !val.length) return [];
|
||||||
return val.map((item) => item.name)
|
return val.map((item) => item.name);
|
||||||
},
|
},
|
||||||
plan_featuresOneListFormatter(val) {
|
plan_featuresOneListFormatter(val) {
|
||||||
if (!val) return ''
|
if (!val) return '';
|
||||||
return val.name
|
return val.name;
|
||||||
},
|
},
|
||||||
plan_featuresManyListFormatterEdit(val) {
|
plan_featuresManyListFormatterEdit(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.name };
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
plan_featuresOneListFormatterEdit(val) {
|
plan_featuresOneListFormatterEdit(val) {
|
||||||
if (!val) return ''
|
if (!val) return '';
|
||||||
return {label: val.name, id: val.id}
|
return { label: val.name, id: val.id };
|
||||||
},
|
},
|
||||||
|
|
||||||
|
usersManyListFormatter(val) {
|
||||||
}
|
if (!val || !val.length) return [];
|
||||||
|
return val.map((item) => item.firstName);
|
||||||
|
},
|
||||||
|
usersOneListFormatter(val) {
|
||||||
|
if (!val) return '';
|
||||||
|
return val.firstName;
|
||||||
|
},
|
||||||
|
usersManyListFormatterEdit(val) {
|
||||||
|
if (!val || !val.length) return [];
|
||||||
|
return val.map((item) => {
|
||||||
|
return { id: item.id, label: item.firstName };
|
||||||
|
});
|
||||||
|
},
|
||||||
|
usersOneListFormatterEdit(val) {
|
||||||
|
if (!val) return '';
|
||||||
|
return { label: val.firstName, id: val.id };
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|||||||
@ -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[] = [
|
||||||
{
|
{
|
||||||
@ -8,21 +8,13 @@ const menuAside: MenuAsideItem[] = [
|
|||||||
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
@ -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,7 +31,6 @@ 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,
|
||||||
@ -50,10 +49,11 @@ 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;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user