Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
151baf7125 | ||
|
|
8156349b96 |
@ -154,7 +154,7 @@ async function awaitResponse(aiRequestId, options = {}) {
|
|||||||
const interval = Math.max(Number(options.interval ?? 5), 1);
|
const interval = Math.max(Number(options.interval ?? 5), 1);
|
||||||
const deadline = Date.now() + Math.max(timeout, interval) * 1000;
|
const deadline = Date.now() + Math.max(timeout, interval) * 1000;
|
||||||
|
|
||||||
while (true) {
|
while (Date.now() < deadline) {
|
||||||
const statusResp = await fetchStatus(aiRequestId, {
|
const statusResp = await fetchStatus(aiRequestId, {
|
||||||
headers: options.headers,
|
headers: options.headers,
|
||||||
timeout: options.timeout_per_call,
|
timeout: options.timeout_per_call,
|
||||||
@ -184,16 +184,14 @@ async function awaitResponse(aiRequestId, options = {}) {
|
|||||||
return statusResp;
|
return statusResp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Date.now() >= deadline) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: "timeout",
|
|
||||||
message: "Timed out waiting for AI response.",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
await sleep(interval * 1000);
|
await sleep(interval * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: "timeout",
|
||||||
|
message: "Timed out waiting for AI response.",
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractText(response) {
|
function extractText(response) {
|
||||||
|
|||||||
@ -56,7 +56,7 @@ passport.use(new MicrosoftStrategy({
|
|||||||
));
|
));
|
||||||
|
|
||||||
function socialStrategy(email, profile, provider, done) {
|
function socialStrategy(email, profile, provider, done) {
|
||||||
db.users.findOrCreate({where: {email, provider}}).then(([user, created]) => {
|
db.users.findOrCreate({where: {email, provider}}).then(([user]) => {
|
||||||
const body = {
|
const body = {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
email: user.email,
|
email: user.email,
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
|
|
||||||
const db = require('../models');
|
const db = require('../models');
|
||||||
const FileDBApi = require('./file');
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const Utils = require('../utils');
|
const Utils = require('../utils');
|
||||||
|
const { applySchoolScope, applySchoolScopeById, assertRecordInCurrentSchool, assertRelatedRecordInCurrentSchool, resolveSchoolIdForMutation } = require('./schoolScope');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -49,18 +48,21 @@ module.exports = class AssessmentsDBApi {
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
await assessments.setSchool( data.school || null, {
|
await assessments.setSchool(resolveSchoolIdForMutation(data.school, currentUser), {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await assertRelatedRecordInCurrentSchool('students', data.student, currentUser, 'schoolId', { transaction });
|
||||||
await assessments.setStudent( data.student || null, {
|
await assessments.setStudent( data.student || null, {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await assertRelatedRecordInCurrentSchool('subjects', data.subject, currentUser, 'schoolId', { transaction });
|
||||||
await assessments.setSubject( data.subject || null, {
|
await assessments.setSubject( data.subject || null, {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await assertRelatedRecordInCurrentSchool('teachers', data.teacher, currentUser, 'schoolId', { transaction });
|
||||||
await assessments.setTeacher( data.teacher || null, {
|
await assessments.setTeacher( data.teacher || null, {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
@ -105,6 +107,7 @@ module.exports = class AssessmentsDBApi {
|
|||||||
importHash: item.importHash || null,
|
importHash: item.importHash || null,
|
||||||
createdById: currentUser.id,
|
createdById: currentUser.id,
|
||||||
updatedById: currentUser.id,
|
updatedById: currentUser.id,
|
||||||
|
schoolId: resolveSchoolIdForMutation(item.school, currentUser),
|
||||||
createdAt: new Date(Date.now() + index * 1000),
|
createdAt: new Date(Date.now() + index * 1000),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -120,9 +123,8 @@ module.exports = class AssessmentsDBApi {
|
|||||||
static async update(id, data, options) {
|
static async update(id, data, options) {
|
||||||
const currentUser = (options && options.currentUser) || {id: null};
|
const currentUser = (options && options.currentUser) || {id: null};
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
const globalAccess = currentUser.app_role?.globalAccess;
|
|
||||||
|
|
||||||
const assessments = await db.assessments.findByPk(id, {}, {transaction});
|
const assessments = await db.assessments.findByPk(id, {}, {transaction});
|
||||||
|
assertRecordInCurrentSchool(assessments, currentUser, 'schoolId');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -150,13 +152,14 @@ module.exports = class AssessmentsDBApi {
|
|||||||
if (data.school !== undefined) {
|
if (data.school !== undefined) {
|
||||||
await assessments.setSchool(
|
await assessments.setSchool(
|
||||||
|
|
||||||
data.school,
|
resolveSchoolIdForMutation(data.school, currentUser),
|
||||||
|
|
||||||
{ transaction }
|
{ transaction }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.student !== undefined) {
|
if (data.student !== undefined) {
|
||||||
|
await assertRelatedRecordInCurrentSchool('students', data.student, currentUser, 'schoolId', { transaction });
|
||||||
await assessments.setStudent(
|
await assessments.setStudent(
|
||||||
|
|
||||||
data.student,
|
data.student,
|
||||||
@ -166,6 +169,7 @@ module.exports = class AssessmentsDBApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (data.subject !== undefined) {
|
if (data.subject !== undefined) {
|
||||||
|
await assertRelatedRecordInCurrentSchool('subjects', data.subject, currentUser, 'schoolId', { transaction });
|
||||||
await assessments.setSubject(
|
await assessments.setSubject(
|
||||||
|
|
||||||
data.subject,
|
data.subject,
|
||||||
@ -175,6 +179,7 @@ module.exports = class AssessmentsDBApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (data.teacher !== undefined) {
|
if (data.teacher !== undefined) {
|
||||||
|
await assertRelatedRecordInCurrentSchool('teachers', data.teacher, currentUser, 'schoolId', { transaction });
|
||||||
await assessments.setTeacher(
|
await assessments.setTeacher(
|
||||||
|
|
||||||
data.teacher,
|
data.teacher,
|
||||||
@ -205,6 +210,8 @@ module.exports = class AssessmentsDBApi {
|
|||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
assessments.forEach((record) => assertRecordInCurrentSchool(record, currentUser, 'schoolId'));
|
||||||
|
|
||||||
await db.sequelize.transaction(async (transaction) => {
|
await db.sequelize.transaction(async (transaction) => {
|
||||||
for (const record of assessments) {
|
for (const record of assessments) {
|
||||||
await record.update(
|
await record.update(
|
||||||
@ -226,6 +233,7 @@ module.exports = class AssessmentsDBApi {
|
|||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
|
||||||
const assessments = await db.assessments.findByPk(id, options);
|
const assessments = await db.assessments.findByPk(id, options);
|
||||||
|
assertRecordInCurrentSchool(assessments, currentUser, 'schoolId');
|
||||||
|
|
||||||
await assessments.update({
|
await assessments.update({
|
||||||
deletedBy: currentUser.id
|
deletedBy: currentUser.id
|
||||||
@ -242,6 +250,9 @@ module.exports = class AssessmentsDBApi {
|
|||||||
|
|
||||||
static async findBy(where, options) {
|
static async findBy(where, options) {
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
const currentUser = (options && options.currentUser) || null;
|
||||||
|
|
||||||
|
applySchoolScope(where, currentUser?.app_role?.globalAccess, currentUser, 'schoolId');
|
||||||
|
|
||||||
const assessments = await db.assessments.findOne(
|
const assessments = await db.assessments.findOne(
|
||||||
{ where },
|
{ where },
|
||||||
@ -309,26 +320,11 @@ module.exports = class AssessmentsDBApi {
|
|||||||
let offset = 0;
|
let offset = 0;
|
||||||
let where = {};
|
let where = {};
|
||||||
const currentPage = +filter.page;
|
const currentPage = +filter.page;
|
||||||
|
|
||||||
|
|
||||||
const user = (options && options.currentUser) || null;
|
const user = (options && options.currentUser) || null;
|
||||||
const userSchools = (user && user.schools?.id) || null;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (userSchools) {
|
|
||||||
if (options?.currentUser?.schoolsId) {
|
|
||||||
where.schoolsId = options.currentUser.schoolsId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
offset = currentPage * limit;
|
offset = currentPage * limit;
|
||||||
|
|
||||||
const orderBy = null;
|
|
||||||
|
|
||||||
const transaction = (options && options.transaction) || undefined;
|
|
||||||
|
|
||||||
let include = [
|
let include = [
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -530,11 +526,7 @@ module.exports = class AssessmentsDBApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
applySchoolScope(where, globalAccess, user, 'schoolId');
|
||||||
if (globalAccess) {
|
|
||||||
delete where.schoolsId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const queryOptions = {
|
const queryOptions = {
|
||||||
where,
|
where,
|
||||||
@ -565,14 +557,9 @@ module.exports = class AssessmentsDBApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async findAllAutocomplete(query, limit, offset, globalAccess, organizationId,) {
|
static async findAllAutocomplete(query, limit, offset, globalAccess, schoolId,) {
|
||||||
let where = {};
|
let where = {};
|
||||||
|
|
||||||
|
|
||||||
if (!globalAccess && organizationId) {
|
|
||||||
where.organizationId = organizationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (query) {
|
if (query) {
|
||||||
where = {
|
where = {
|
||||||
@ -587,6 +574,8 @@ module.exports = class AssessmentsDBApi {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applySchoolScopeById(where, globalAccess, schoolId, 'schoolId');
|
||||||
|
|
||||||
const records = await db.assessments.findAll({
|
const records = await db.assessments.findAll({
|
||||||
attributes: [ 'id', 'tipo' ],
|
attributes: [ 'id', 'tipo' ],
|
||||||
where,
|
where,
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
|
|
||||||
const db = require('../models');
|
const db = require('../models');
|
||||||
const FileDBApi = require('./file');
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const Utils = require('../utils');
|
const Utils = require('../utils');
|
||||||
|
const { applySchoolScope, applySchoolScopeById, assertRecordInCurrentSchool, assertRelatedRecordInCurrentSchool, resolveSchoolIdForMutation } = require('./schoolScope');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -45,10 +44,11 @@ module.exports = class AttendanceDBApi {
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
await attendance.setSchool( data.school || null, {
|
await attendance.setSchool(resolveSchoolIdForMutation(data.school, currentUser), {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await assertRelatedRecordInCurrentSchool('students', data.student, currentUser, 'schoolId', { transaction });
|
||||||
await attendance.setStudent( data.student || null, {
|
await attendance.setStudent( data.student || null, {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
@ -89,6 +89,7 @@ module.exports = class AttendanceDBApi {
|
|||||||
importHash: item.importHash || null,
|
importHash: item.importHash || null,
|
||||||
createdById: currentUser.id,
|
createdById: currentUser.id,
|
||||||
updatedById: currentUser.id,
|
updatedById: currentUser.id,
|
||||||
|
schoolId: resolveSchoolIdForMutation(item.school, currentUser),
|
||||||
createdAt: new Date(Date.now() + index * 1000),
|
createdAt: new Date(Date.now() + index * 1000),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -104,9 +105,8 @@ module.exports = class AttendanceDBApi {
|
|||||||
static async update(id, data, options) {
|
static async update(id, data, options) {
|
||||||
const currentUser = (options && options.currentUser) || {id: null};
|
const currentUser = (options && options.currentUser) || {id: null};
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
const globalAccess = currentUser.app_role?.globalAccess;
|
|
||||||
|
|
||||||
const attendance = await db.attendance.findByPk(id, {}, {transaction});
|
const attendance = await db.attendance.findByPk(id, {}, {transaction});
|
||||||
|
assertRecordInCurrentSchool(attendance, currentUser, 'schoolId');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -131,13 +131,14 @@ module.exports = class AttendanceDBApi {
|
|||||||
if (data.school !== undefined) {
|
if (data.school !== undefined) {
|
||||||
await attendance.setSchool(
|
await attendance.setSchool(
|
||||||
|
|
||||||
data.school,
|
resolveSchoolIdForMutation(data.school, currentUser),
|
||||||
|
|
||||||
{ transaction }
|
{ transaction }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.student !== undefined) {
|
if (data.student !== undefined) {
|
||||||
|
await assertRelatedRecordInCurrentSchool('students', data.student, currentUser, 'schoolId', { transaction });
|
||||||
await attendance.setStudent(
|
await attendance.setStudent(
|
||||||
|
|
||||||
data.student,
|
data.student,
|
||||||
@ -168,6 +169,8 @@ module.exports = class AttendanceDBApi {
|
|||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
attendance.forEach((record) => assertRecordInCurrentSchool(record, currentUser, 'schoolId'));
|
||||||
|
|
||||||
await db.sequelize.transaction(async (transaction) => {
|
await db.sequelize.transaction(async (transaction) => {
|
||||||
for (const record of attendance) {
|
for (const record of attendance) {
|
||||||
await record.update(
|
await record.update(
|
||||||
@ -189,6 +192,7 @@ module.exports = class AttendanceDBApi {
|
|||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
|
||||||
const attendance = await db.attendance.findByPk(id, options);
|
const attendance = await db.attendance.findByPk(id, options);
|
||||||
|
assertRecordInCurrentSchool(attendance, currentUser, 'schoolId');
|
||||||
|
|
||||||
await attendance.update({
|
await attendance.update({
|
||||||
deletedBy: currentUser.id
|
deletedBy: currentUser.id
|
||||||
@ -205,6 +209,9 @@ module.exports = class AttendanceDBApi {
|
|||||||
|
|
||||||
static async findBy(where, options) {
|
static async findBy(where, options) {
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
const currentUser = (options && options.currentUser) || null;
|
||||||
|
|
||||||
|
applySchoolScope(where, currentUser?.app_role?.globalAccess, currentUser, 'schoolId');
|
||||||
|
|
||||||
const attendance = await db.attendance.findOne(
|
const attendance = await db.attendance.findOne(
|
||||||
{ where },
|
{ where },
|
||||||
@ -262,26 +269,11 @@ module.exports = class AttendanceDBApi {
|
|||||||
let offset = 0;
|
let offset = 0;
|
||||||
let where = {};
|
let where = {};
|
||||||
const currentPage = +filter.page;
|
const currentPage = +filter.page;
|
||||||
|
|
||||||
|
|
||||||
const user = (options && options.currentUser) || null;
|
const user = (options && options.currentUser) || null;
|
||||||
const userSchools = (user && user.schools?.id) || null;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (userSchools) {
|
|
||||||
if (options?.currentUser?.schoolsId) {
|
|
||||||
where.schoolsId = options.currentUser.schoolsId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
offset = currentPage * limit;
|
offset = currentPage * limit;
|
||||||
|
|
||||||
const orderBy = null;
|
|
||||||
|
|
||||||
const transaction = (options && options.transaction) || undefined;
|
|
||||||
|
|
||||||
let include = [
|
let include = [
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -421,11 +413,7 @@ module.exports = class AttendanceDBApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
applySchoolScope(where, globalAccess, user, 'schoolId');
|
||||||
if (globalAccess) {
|
|
||||||
delete where.schoolsId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const queryOptions = {
|
const queryOptions = {
|
||||||
where,
|
where,
|
||||||
@ -456,14 +444,9 @@ module.exports = class AttendanceDBApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async findAllAutocomplete(query, limit, offset, globalAccess, organizationId,) {
|
static async findAllAutocomplete(query, limit, offset, globalAccess, schoolId,) {
|
||||||
let where = {};
|
let where = {};
|
||||||
|
|
||||||
|
|
||||||
if (!globalAccess && organizationId) {
|
|
||||||
where.organizationId = organizationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (query) {
|
if (query) {
|
||||||
where = {
|
where = {
|
||||||
@ -478,6 +461,8 @@ module.exports = class AttendanceDBApi {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applySchoolScopeById(where, globalAccess, schoolId, 'schoolId');
|
||||||
|
|
||||||
const records = await db.attendance.findAll({
|
const records = await db.attendance.findAll({
|
||||||
attributes: [ 'id', 'observacao' ],
|
attributes: [ 'id', 'observacao' ],
|
||||||
where,
|
where,
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
|
|
||||||
const db = require('../models');
|
const db = require('../models');
|
||||||
const FileDBApi = require('./file');
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const Utils = require('../utils');
|
const Utils = require('../utils');
|
||||||
|
const { applySchoolScope, applySchoolScopeById, assertRecordInCurrentSchool, assertRelatedRecordInCurrentSchool, resolveSchoolIdForMutation } = require('./schoolScope');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -54,14 +53,16 @@ module.exports = class Book_loansDBApi {
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
await book_loans.setSchool( data.school || null, {
|
await book_loans.setSchool(resolveSchoolIdForMutation(data.school, currentUser), {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await assertRelatedRecordInCurrentSchool('books', data.book, currentUser, 'schoolId', { transaction });
|
||||||
await book_loans.setBook( data.book || null, {
|
await book_loans.setBook( data.book || null, {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await assertRelatedRecordInCurrentSchool('students', data.student, currentUser, 'schoolId', { transaction });
|
||||||
await book_loans.setStudent( data.student || null, {
|
await book_loans.setStudent( data.student || null, {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
@ -111,6 +112,7 @@ module.exports = class Book_loansDBApi {
|
|||||||
importHash: item.importHash || null,
|
importHash: item.importHash || null,
|
||||||
createdById: currentUser.id,
|
createdById: currentUser.id,
|
||||||
updatedById: currentUser.id,
|
updatedById: currentUser.id,
|
||||||
|
schoolId: resolveSchoolIdForMutation(item.school, currentUser),
|
||||||
createdAt: new Date(Date.now() + index * 1000),
|
createdAt: new Date(Date.now() + index * 1000),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -126,9 +128,8 @@ module.exports = class Book_loansDBApi {
|
|||||||
static async update(id, data, options) {
|
static async update(id, data, options) {
|
||||||
const currentUser = (options && options.currentUser) || {id: null};
|
const currentUser = (options && options.currentUser) || {id: null};
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
const globalAccess = currentUser.app_role?.globalAccess;
|
|
||||||
|
|
||||||
const book_loans = await db.book_loans.findByPk(id, {}, {transaction});
|
const book_loans = await db.book_loans.findByPk(id, {}, {transaction});
|
||||||
|
assertRecordInCurrentSchool(book_loans, currentUser, 'schoolId');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -159,13 +160,14 @@ module.exports = class Book_loansDBApi {
|
|||||||
if (data.school !== undefined) {
|
if (data.school !== undefined) {
|
||||||
await book_loans.setSchool(
|
await book_loans.setSchool(
|
||||||
|
|
||||||
data.school,
|
resolveSchoolIdForMutation(data.school, currentUser),
|
||||||
|
|
||||||
{ transaction }
|
{ transaction }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.book !== undefined) {
|
if (data.book !== undefined) {
|
||||||
|
await assertRelatedRecordInCurrentSchool('books', data.book, currentUser, 'schoolId', { transaction });
|
||||||
await book_loans.setBook(
|
await book_loans.setBook(
|
||||||
|
|
||||||
data.book,
|
data.book,
|
||||||
@ -175,6 +177,7 @@ module.exports = class Book_loansDBApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (data.student !== undefined) {
|
if (data.student !== undefined) {
|
||||||
|
await assertRelatedRecordInCurrentSchool('students', data.student, currentUser, 'schoolId', { transaction });
|
||||||
await book_loans.setStudent(
|
await book_loans.setStudent(
|
||||||
|
|
||||||
data.student,
|
data.student,
|
||||||
@ -205,6 +208,8 @@ module.exports = class Book_loansDBApi {
|
|||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
book_loans.forEach((record) => assertRecordInCurrentSchool(record, currentUser, 'schoolId'));
|
||||||
|
|
||||||
await db.sequelize.transaction(async (transaction) => {
|
await db.sequelize.transaction(async (transaction) => {
|
||||||
for (const record of book_loans) {
|
for (const record of book_loans) {
|
||||||
await record.update(
|
await record.update(
|
||||||
@ -226,6 +231,7 @@ module.exports = class Book_loansDBApi {
|
|||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
|
||||||
const book_loans = await db.book_loans.findByPk(id, options);
|
const book_loans = await db.book_loans.findByPk(id, options);
|
||||||
|
assertRecordInCurrentSchool(book_loans, currentUser, 'schoolId');
|
||||||
|
|
||||||
await book_loans.update({
|
await book_loans.update({
|
||||||
deletedBy: currentUser.id
|
deletedBy: currentUser.id
|
||||||
@ -242,6 +248,9 @@ module.exports = class Book_loansDBApi {
|
|||||||
|
|
||||||
static async findBy(where, options) {
|
static async findBy(where, options) {
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
const currentUser = (options && options.currentUser) || null;
|
||||||
|
|
||||||
|
applySchoolScope(where, currentUser?.app_role?.globalAccess, currentUser, 'schoolId');
|
||||||
|
|
||||||
const book_loans = await db.book_loans.findOne(
|
const book_loans = await db.book_loans.findOne(
|
||||||
{ where },
|
{ where },
|
||||||
@ -304,26 +313,11 @@ module.exports = class Book_loansDBApi {
|
|||||||
let offset = 0;
|
let offset = 0;
|
||||||
let where = {};
|
let where = {};
|
||||||
const currentPage = +filter.page;
|
const currentPage = +filter.page;
|
||||||
|
|
||||||
|
|
||||||
const user = (options && options.currentUser) || null;
|
const user = (options && options.currentUser) || null;
|
||||||
const userSchools = (user && user.schools?.id) || null;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (userSchools) {
|
|
||||||
if (options?.currentUser?.schoolsId) {
|
|
||||||
where.schoolsId = options.currentUser.schoolsId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
offset = currentPage * limit;
|
offset = currentPage * limit;
|
||||||
|
|
||||||
const orderBy = null;
|
|
||||||
|
|
||||||
const transaction = (options && options.transaction) || undefined;
|
|
||||||
|
|
||||||
let include = [
|
let include = [
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -561,11 +555,7 @@ module.exports = class Book_loansDBApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
applySchoolScope(where, globalAccess, user, 'schoolId');
|
||||||
if (globalAccess) {
|
|
||||||
delete where.schoolsId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const queryOptions = {
|
const queryOptions = {
|
||||||
where,
|
where,
|
||||||
@ -596,14 +586,9 @@ module.exports = class Book_loansDBApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async findAllAutocomplete(query, limit, offset, globalAccess, organizationId,) {
|
static async findAllAutocomplete(query, limit, offset, globalAccess, schoolId,) {
|
||||||
let where = {};
|
let where = {};
|
||||||
|
|
||||||
|
|
||||||
if (!globalAccess && organizationId) {
|
|
||||||
where.organizationId = organizationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (query) {
|
if (query) {
|
||||||
where = {
|
where = {
|
||||||
@ -618,6 +603,8 @@ module.exports = class Book_loansDBApi {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applySchoolScopeById(where, globalAccess, schoolId, 'schoolId');
|
||||||
|
|
||||||
const records = await db.book_loans.findAll({
|
const records = await db.book_loans.findAll({
|
||||||
attributes: [ 'id', 'status' ],
|
attributes: [ 'id', 'status' ],
|
||||||
where,
|
where,
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
|
|
||||||
const db = require('../models');
|
const db = require('../models');
|
||||||
const FileDBApi = require('./file');
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const Utils = require('../utils');
|
const Utils = require('../utils');
|
||||||
|
const { applySchoolScope, applySchoolScopeById, assertRecordInCurrentSchool, resolveSchoolIdForMutation } = require('./schoolScope');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -59,7 +58,7 @@ module.exports = class BooksDBApi {
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
await books.setSchool( data.school || null, {
|
await books.setSchool(resolveSchoolIdForMutation(data.school, currentUser), {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -113,6 +112,7 @@ module.exports = class BooksDBApi {
|
|||||||
importHash: item.importHash || null,
|
importHash: item.importHash || null,
|
||||||
createdById: currentUser.id,
|
createdById: currentUser.id,
|
||||||
updatedById: currentUser.id,
|
updatedById: currentUser.id,
|
||||||
|
schoolId: resolveSchoolIdForMutation(item.school, currentUser),
|
||||||
createdAt: new Date(Date.now() + index * 1000),
|
createdAt: new Date(Date.now() + index * 1000),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -128,9 +128,8 @@ module.exports = class BooksDBApi {
|
|||||||
static async update(id, data, options) {
|
static async update(id, data, options) {
|
||||||
const currentUser = (options && options.currentUser) || {id: null};
|
const currentUser = (options && options.currentUser) || {id: null};
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
const globalAccess = currentUser.app_role?.globalAccess;
|
|
||||||
|
|
||||||
const books = await db.books.findByPk(id, {}, {transaction});
|
const books = await db.books.findByPk(id, {}, {transaction});
|
||||||
|
assertRecordInCurrentSchool(books, currentUser, 'schoolId');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -164,7 +163,7 @@ module.exports = class BooksDBApi {
|
|||||||
if (data.school !== undefined) {
|
if (data.school !== undefined) {
|
||||||
await books.setSchool(
|
await books.setSchool(
|
||||||
|
|
||||||
data.school,
|
resolveSchoolIdForMutation(data.school, currentUser),
|
||||||
|
|
||||||
{ transaction }
|
{ transaction }
|
||||||
);
|
);
|
||||||
@ -192,6 +191,8 @@ module.exports = class BooksDBApi {
|
|||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
books.forEach((record) => assertRecordInCurrentSchool(record, currentUser, 'schoolId'));
|
||||||
|
|
||||||
await db.sequelize.transaction(async (transaction) => {
|
await db.sequelize.transaction(async (transaction) => {
|
||||||
for (const record of books) {
|
for (const record of books) {
|
||||||
await record.update(
|
await record.update(
|
||||||
@ -213,6 +214,7 @@ module.exports = class BooksDBApi {
|
|||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
|
||||||
const books = await db.books.findByPk(id, options);
|
const books = await db.books.findByPk(id, options);
|
||||||
|
assertRecordInCurrentSchool(books, currentUser, 'schoolId');
|
||||||
|
|
||||||
await books.update({
|
await books.update({
|
||||||
deletedBy: currentUser.id
|
deletedBy: currentUser.id
|
||||||
@ -229,6 +231,9 @@ module.exports = class BooksDBApi {
|
|||||||
|
|
||||||
static async findBy(where, options) {
|
static async findBy(where, options) {
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
const currentUser = (options && options.currentUser) || null;
|
||||||
|
|
||||||
|
applySchoolScope(where, currentUser?.app_role?.globalAccess, currentUser, 'schoolId');
|
||||||
|
|
||||||
const books = await db.books.findOne(
|
const books = await db.books.findOne(
|
||||||
{ where },
|
{ where },
|
||||||
@ -285,26 +290,11 @@ module.exports = class BooksDBApi {
|
|||||||
let offset = 0;
|
let offset = 0;
|
||||||
let where = {};
|
let where = {};
|
||||||
const currentPage = +filter.page;
|
const currentPage = +filter.page;
|
||||||
|
|
||||||
|
|
||||||
const user = (options && options.currentUser) || null;
|
const user = (options && options.currentUser) || null;
|
||||||
const userSchools = (user && user.schools?.id) || null;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (userSchools) {
|
|
||||||
if (options?.currentUser?.schoolsId) {
|
|
||||||
where.schoolsId = options.currentUser.schoolsId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
offset = currentPage * limit;
|
offset = currentPage * limit;
|
||||||
|
|
||||||
const orderBy = null;
|
|
||||||
|
|
||||||
const transaction = (options && options.transaction) || undefined;
|
|
||||||
|
|
||||||
let include = [
|
let include = [
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -471,11 +461,7 @@ module.exports = class BooksDBApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
applySchoolScope(where, globalAccess, user, 'schoolId');
|
||||||
if (globalAccess) {
|
|
||||||
delete where.schoolsId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const queryOptions = {
|
const queryOptions = {
|
||||||
where,
|
where,
|
||||||
@ -506,14 +492,9 @@ module.exports = class BooksDBApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async findAllAutocomplete(query, limit, offset, globalAccess, organizationId,) {
|
static async findAllAutocomplete(query, limit, offset, globalAccess, schoolId,) {
|
||||||
let where = {};
|
let where = {};
|
||||||
|
|
||||||
|
|
||||||
if (!globalAccess && organizationId) {
|
|
||||||
where.organizationId = organizationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (query) {
|
if (query) {
|
||||||
where = {
|
where = {
|
||||||
@ -528,6 +509,8 @@ module.exports = class BooksDBApi {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applySchoolScopeById(where, globalAccess, schoolId, 'schoolId');
|
||||||
|
|
||||||
const records = await db.books.findAll({
|
const records = await db.books.findAll({
|
||||||
attributes: [ 'id', 'titulo' ],
|
attributes: [ 'id', 'titulo' ],
|
||||||
where,
|
where,
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
|
|
||||||
const db = require('../models');
|
const db = require('../models');
|
||||||
const FileDBApi = require('./file');
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const Utils = require('../utils');
|
const Utils = require('../utils');
|
||||||
|
const { applySchoolScope, applySchoolScopeById, assertRecordInCurrentSchool, assertRelatedRecordInCurrentSchool, resolveSchoolIdForMutation } = require('./schoolScope');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -54,10 +53,11 @@ module.exports = class ClassesDBApi {
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
await classes.setSchool( data.school || null, {
|
await classes.setSchool(resolveSchoolIdForMutation(data.school, currentUser), {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await assertRelatedRecordInCurrentSchool('grades', data.grade, currentUser, 'schoolId', { transaction });
|
||||||
await classes.setGrade( data.grade || null, {
|
await classes.setGrade( data.grade || null, {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
@ -107,6 +107,7 @@ module.exports = class ClassesDBApi {
|
|||||||
importHash: item.importHash || null,
|
importHash: item.importHash || null,
|
||||||
createdById: currentUser.id,
|
createdById: currentUser.id,
|
||||||
updatedById: currentUser.id,
|
updatedById: currentUser.id,
|
||||||
|
schoolId: resolveSchoolIdForMutation(item.school, currentUser),
|
||||||
createdAt: new Date(Date.now() + index * 1000),
|
createdAt: new Date(Date.now() + index * 1000),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -122,9 +123,8 @@ module.exports = class ClassesDBApi {
|
|||||||
static async update(id, data, options) {
|
static async update(id, data, options) {
|
||||||
const currentUser = (options && options.currentUser) || {id: null};
|
const currentUser = (options && options.currentUser) || {id: null};
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
const globalAccess = currentUser.app_role?.globalAccess;
|
|
||||||
|
|
||||||
const classes = await db.classes.findByPk(id, {}, {transaction});
|
const classes = await db.classes.findByPk(id, {}, {transaction});
|
||||||
|
assertRecordInCurrentSchool(classes, currentUser, 'schoolId');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -155,13 +155,14 @@ module.exports = class ClassesDBApi {
|
|||||||
if (data.school !== undefined) {
|
if (data.school !== undefined) {
|
||||||
await classes.setSchool(
|
await classes.setSchool(
|
||||||
|
|
||||||
data.school,
|
resolveSchoolIdForMutation(data.school, currentUser),
|
||||||
|
|
||||||
{ transaction }
|
{ transaction }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.grade !== undefined) {
|
if (data.grade !== undefined) {
|
||||||
|
await assertRelatedRecordInCurrentSchool('grades', data.grade, currentUser, 'schoolId', { transaction });
|
||||||
await classes.setGrade(
|
await classes.setGrade(
|
||||||
|
|
||||||
data.grade,
|
data.grade,
|
||||||
@ -192,6 +193,8 @@ module.exports = class ClassesDBApi {
|
|||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
classes.forEach((record) => assertRecordInCurrentSchool(record, currentUser, 'schoolId'));
|
||||||
|
|
||||||
await db.sequelize.transaction(async (transaction) => {
|
await db.sequelize.transaction(async (transaction) => {
|
||||||
for (const record of classes) {
|
for (const record of classes) {
|
||||||
await record.update(
|
await record.update(
|
||||||
@ -213,6 +216,7 @@ module.exports = class ClassesDBApi {
|
|||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
|
||||||
const classes = await db.classes.findByPk(id, options);
|
const classes = await db.classes.findByPk(id, options);
|
||||||
|
assertRecordInCurrentSchool(classes, currentUser, 'schoolId');
|
||||||
|
|
||||||
await classes.update({
|
await classes.update({
|
||||||
deletedBy: currentUser.id
|
deletedBy: currentUser.id
|
||||||
@ -229,6 +233,9 @@ module.exports = class ClassesDBApi {
|
|||||||
|
|
||||||
static async findBy(where, options) {
|
static async findBy(where, options) {
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
const currentUser = (options && options.currentUser) || null;
|
||||||
|
|
||||||
|
applySchoolScope(where, currentUser?.app_role?.globalAccess, currentUser, 'schoolId');
|
||||||
|
|
||||||
const classes = await db.classes.findOne(
|
const classes = await db.classes.findOne(
|
||||||
{ where },
|
{ where },
|
||||||
@ -290,26 +297,11 @@ module.exports = class ClassesDBApi {
|
|||||||
let offset = 0;
|
let offset = 0;
|
||||||
let where = {};
|
let where = {};
|
||||||
const currentPage = +filter.page;
|
const currentPage = +filter.page;
|
||||||
|
|
||||||
|
|
||||||
const user = (options && options.currentUser) || null;
|
const user = (options && options.currentUser) || null;
|
||||||
const userSchools = (user && user.schools?.id) || null;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (userSchools) {
|
|
||||||
if (options?.currentUser?.schoolsId) {
|
|
||||||
where.schoolsId = options.currentUser.schoolsId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
offset = currentPage * limit;
|
offset = currentPage * limit;
|
||||||
|
|
||||||
const orderBy = null;
|
|
||||||
|
|
||||||
const transaction = (options && options.transaction) || undefined;
|
|
||||||
|
|
||||||
let include = [
|
let include = [
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -467,11 +459,7 @@ module.exports = class ClassesDBApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
applySchoolScope(where, globalAccess, user, 'schoolId');
|
||||||
if (globalAccess) {
|
|
||||||
delete where.schoolsId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const queryOptions = {
|
const queryOptions = {
|
||||||
where,
|
where,
|
||||||
@ -502,14 +490,9 @@ module.exports = class ClassesDBApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async findAllAutocomplete(query, limit, offset, globalAccess, organizationId,) {
|
static async findAllAutocomplete(query, limit, offset, globalAccess, schoolId,) {
|
||||||
let where = {};
|
let where = {};
|
||||||
|
|
||||||
|
|
||||||
if (!globalAccess && organizationId) {
|
|
||||||
where.organizationId = organizationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (query) {
|
if (query) {
|
||||||
where = {
|
where = {
|
||||||
@ -524,6 +507,8 @@ module.exports = class ClassesDBApi {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applySchoolScopeById(where, globalAccess, schoolId, 'schoolId');
|
||||||
|
|
||||||
const records = await db.classes.findAll({
|
const records = await db.classes.findAll({
|
||||||
attributes: [ 'id', 'nome' ],
|
attributes: [ 'id', 'nome' ],
|
||||||
where,
|
where,
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
|
|
||||||
const db = require('../models');
|
const db = require('../models');
|
||||||
const FileDBApi = require('./file');
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const Utils = require('../utils');
|
const Utils = require('../utils');
|
||||||
|
const { applySchoolScope, applySchoolScopeById, assertRecordInCurrentSchool, resolveSchoolIdForMutation } = require('./schoolScope');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -44,7 +43,7 @@ module.exports = class CoursesDBApi {
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
await courses.setSchool( data.school || null, {
|
await courses.setSchool(resolveSchoolIdForMutation(data.school, currentUser), {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -83,6 +82,7 @@ module.exports = class CoursesDBApi {
|
|||||||
importHash: item.importHash || null,
|
importHash: item.importHash || null,
|
||||||
createdById: currentUser.id,
|
createdById: currentUser.id,
|
||||||
updatedById: currentUser.id,
|
updatedById: currentUser.id,
|
||||||
|
schoolId: resolveSchoolIdForMutation(item.school, currentUser),
|
||||||
createdAt: new Date(Date.now() + index * 1000),
|
createdAt: new Date(Date.now() + index * 1000),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -98,9 +98,8 @@ module.exports = class CoursesDBApi {
|
|||||||
static async update(id, data, options) {
|
static async update(id, data, options) {
|
||||||
const currentUser = (options && options.currentUser) || {id: null};
|
const currentUser = (options && options.currentUser) || {id: null};
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
const globalAccess = currentUser.app_role?.globalAccess;
|
|
||||||
|
|
||||||
const courses = await db.courses.findByPk(id, {}, {transaction});
|
const courses = await db.courses.findByPk(id, {}, {transaction});
|
||||||
|
assertRecordInCurrentSchool(courses, currentUser, 'schoolId');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -125,7 +124,7 @@ module.exports = class CoursesDBApi {
|
|||||||
if (data.school !== undefined) {
|
if (data.school !== undefined) {
|
||||||
await courses.setSchool(
|
await courses.setSchool(
|
||||||
|
|
||||||
data.school,
|
resolveSchoolIdForMutation(data.school, currentUser),
|
||||||
|
|
||||||
{ transaction }
|
{ transaction }
|
||||||
);
|
);
|
||||||
@ -153,6 +152,8 @@ module.exports = class CoursesDBApi {
|
|||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
courses.forEach((record) => assertRecordInCurrentSchool(record, currentUser, 'schoolId'));
|
||||||
|
|
||||||
await db.sequelize.transaction(async (transaction) => {
|
await db.sequelize.transaction(async (transaction) => {
|
||||||
for (const record of courses) {
|
for (const record of courses) {
|
||||||
await record.update(
|
await record.update(
|
||||||
@ -174,6 +175,7 @@ module.exports = class CoursesDBApi {
|
|||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
|
||||||
const courses = await db.courses.findByPk(id, options);
|
const courses = await db.courses.findByPk(id, options);
|
||||||
|
assertRecordInCurrentSchool(courses, currentUser, 'schoolId');
|
||||||
|
|
||||||
await courses.update({
|
await courses.update({
|
||||||
deletedBy: currentUser.id
|
deletedBy: currentUser.id
|
||||||
@ -190,6 +192,9 @@ module.exports = class CoursesDBApi {
|
|||||||
|
|
||||||
static async findBy(where, options) {
|
static async findBy(where, options) {
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
const currentUser = (options && options.currentUser) || null;
|
||||||
|
|
||||||
|
applySchoolScope(where, currentUser?.app_role?.globalAccess, currentUser, 'schoolId');
|
||||||
|
|
||||||
const courses = await db.courses.findOne(
|
const courses = await db.courses.findOne(
|
||||||
{ where },
|
{ where },
|
||||||
@ -242,26 +247,11 @@ module.exports = class CoursesDBApi {
|
|||||||
let offset = 0;
|
let offset = 0;
|
||||||
let where = {};
|
let where = {};
|
||||||
const currentPage = +filter.page;
|
const currentPage = +filter.page;
|
||||||
|
|
||||||
|
|
||||||
const user = (options && options.currentUser) || null;
|
const user = (options && options.currentUser) || null;
|
||||||
const userSchools = (user && user.schools?.id) || null;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (userSchools) {
|
|
||||||
if (options?.currentUser?.schoolsId) {
|
|
||||||
where.schoolsId = options.currentUser.schoolsId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
offset = currentPage * limit;
|
offset = currentPage * limit;
|
||||||
|
|
||||||
const orderBy = null;
|
|
||||||
|
|
||||||
const transaction = (options && options.transaction) || undefined;
|
|
||||||
|
|
||||||
let include = [
|
let include = [
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -369,11 +359,7 @@ module.exports = class CoursesDBApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
applySchoolScope(where, globalAccess, user, 'schoolId');
|
||||||
if (globalAccess) {
|
|
||||||
delete where.schoolsId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const queryOptions = {
|
const queryOptions = {
|
||||||
where,
|
where,
|
||||||
@ -404,14 +390,9 @@ module.exports = class CoursesDBApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async findAllAutocomplete(query, limit, offset, globalAccess, organizationId,) {
|
static async findAllAutocomplete(query, limit, offset, globalAccess, schoolId,) {
|
||||||
let where = {};
|
let where = {};
|
||||||
|
|
||||||
|
|
||||||
if (!globalAccess && organizationId) {
|
|
||||||
where.organizationId = organizationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (query) {
|
if (query) {
|
||||||
where = {
|
where = {
|
||||||
@ -426,6 +407,8 @@ module.exports = class CoursesDBApi {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applySchoolScopeById(where, globalAccess, schoolId, 'schoolId');
|
||||||
|
|
||||||
const records = await db.courses.findAll({
|
const records = await db.courses.findAll({
|
||||||
attributes: [ 'id', 'nome' ],
|
attributes: [ 'id', 'nome' ],
|
||||||
where,
|
where,
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
|
|
||||||
const db = require('../models');
|
const db = require('../models');
|
||||||
const FileDBApi = require('./file');
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const Utils = require('../utils');
|
const Utils = require('../utils');
|
||||||
|
const { applySchoolScope, applySchoolScopeById, assertRecordInCurrentSchool, resolveSchoolIdForMutation } = require('./schoolScope');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -59,7 +58,7 @@ module.exports = class EmployeesDBApi {
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
await employees.setSchool( data.school || null, {
|
await employees.setSchool(resolveSchoolIdForMutation(data.school, currentUser), {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -113,6 +112,7 @@ module.exports = class EmployeesDBApi {
|
|||||||
importHash: item.importHash || null,
|
importHash: item.importHash || null,
|
||||||
createdById: currentUser.id,
|
createdById: currentUser.id,
|
||||||
updatedById: currentUser.id,
|
updatedById: currentUser.id,
|
||||||
|
schoolId: resolveSchoolIdForMutation(item.school, currentUser),
|
||||||
createdAt: new Date(Date.now() + index * 1000),
|
createdAt: new Date(Date.now() + index * 1000),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -128,9 +128,8 @@ module.exports = class EmployeesDBApi {
|
|||||||
static async update(id, data, options) {
|
static async update(id, data, options) {
|
||||||
const currentUser = (options && options.currentUser) || {id: null};
|
const currentUser = (options && options.currentUser) || {id: null};
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
const globalAccess = currentUser.app_role?.globalAccess;
|
|
||||||
|
|
||||||
const employees = await db.employees.findByPk(id, {}, {transaction});
|
const employees = await db.employees.findByPk(id, {}, {transaction});
|
||||||
|
assertRecordInCurrentSchool(employees, currentUser, 'schoolId');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -164,7 +163,7 @@ module.exports = class EmployeesDBApi {
|
|||||||
if (data.school !== undefined) {
|
if (data.school !== undefined) {
|
||||||
await employees.setSchool(
|
await employees.setSchool(
|
||||||
|
|
||||||
data.school,
|
resolveSchoolIdForMutation(data.school, currentUser),
|
||||||
|
|
||||||
{ transaction }
|
{ transaction }
|
||||||
);
|
);
|
||||||
@ -192,6 +191,8 @@ module.exports = class EmployeesDBApi {
|
|||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
employees.forEach((record) => assertRecordInCurrentSchool(record, currentUser, 'schoolId'));
|
||||||
|
|
||||||
await db.sequelize.transaction(async (transaction) => {
|
await db.sequelize.transaction(async (transaction) => {
|
||||||
for (const record of employees) {
|
for (const record of employees) {
|
||||||
await record.update(
|
await record.update(
|
||||||
@ -213,6 +214,7 @@ module.exports = class EmployeesDBApi {
|
|||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
|
||||||
const employees = await db.employees.findByPk(id, options);
|
const employees = await db.employees.findByPk(id, options);
|
||||||
|
assertRecordInCurrentSchool(employees, currentUser, 'schoolId');
|
||||||
|
|
||||||
await employees.update({
|
await employees.update({
|
||||||
deletedBy: currentUser.id
|
deletedBy: currentUser.id
|
||||||
@ -229,6 +231,9 @@ module.exports = class EmployeesDBApi {
|
|||||||
|
|
||||||
static async findBy(where, options) {
|
static async findBy(where, options) {
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
const currentUser = (options && options.currentUser) || null;
|
||||||
|
|
||||||
|
applySchoolScope(where, currentUser?.app_role?.globalAccess, currentUser, 'schoolId');
|
||||||
|
|
||||||
const employees = await db.employees.findOne(
|
const employees = await db.employees.findOne(
|
||||||
{ where },
|
{ where },
|
||||||
@ -281,26 +286,11 @@ module.exports = class EmployeesDBApi {
|
|||||||
let offset = 0;
|
let offset = 0;
|
||||||
let where = {};
|
let where = {};
|
||||||
const currentPage = +filter.page;
|
const currentPage = +filter.page;
|
||||||
|
|
||||||
|
|
||||||
const user = (options && options.currentUser) || null;
|
const user = (options && options.currentUser) || null;
|
||||||
const userSchools = (user && user.schools?.id) || null;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (userSchools) {
|
|
||||||
if (options?.currentUser?.schoolsId) {
|
|
||||||
where.schoolsId = options.currentUser.schoolsId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
offset = currentPage * limit;
|
offset = currentPage * limit;
|
||||||
|
|
||||||
const orderBy = null;
|
|
||||||
|
|
||||||
const transaction = (options && options.transaction) || undefined;
|
|
||||||
|
|
||||||
let include = [
|
let include = [
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -467,11 +457,7 @@ module.exports = class EmployeesDBApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
applySchoolScope(where, globalAccess, user, 'schoolId');
|
||||||
if (globalAccess) {
|
|
||||||
delete where.schoolsId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const queryOptions = {
|
const queryOptions = {
|
||||||
where,
|
where,
|
||||||
@ -502,14 +488,9 @@ module.exports = class EmployeesDBApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async findAllAutocomplete(query, limit, offset, globalAccess, organizationId,) {
|
static async findAllAutocomplete(query, limit, offset, globalAccess, schoolId,) {
|
||||||
let where = {};
|
let where = {};
|
||||||
|
|
||||||
|
|
||||||
if (!globalAccess && organizationId) {
|
|
||||||
where.organizationId = organizationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (query) {
|
if (query) {
|
||||||
where = {
|
where = {
|
||||||
@ -524,6 +505,8 @@ module.exports = class EmployeesDBApi {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applySchoolScopeById(where, globalAccess, schoolId, 'schoolId');
|
||||||
|
|
||||||
const records = await db.employees.findAll({
|
const records = await db.employees.findAll({
|
||||||
attributes: [ 'id', 'nome' ],
|
attributes: [ 'id', 'nome' ],
|
||||||
where,
|
where,
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
|
|
||||||
const db = require('../models');
|
const db = require('../models');
|
||||||
const FileDBApi = require('./file');
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const Utils = require('../utils');
|
const Utils = require('../utils');
|
||||||
|
const { applySchoolScope, applySchoolScopeById, assertRecordInCurrentSchool, assertRelatedRecordInCurrentSchool, resolveSchoolIdForMutation } = require('./schoolScope');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -44,14 +43,16 @@ module.exports = class EnrollmentsDBApi {
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
await enrollments.setSchool( data.school || null, {
|
await enrollments.setSchool(resolveSchoolIdForMutation(data.school, currentUser), {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await assertRelatedRecordInCurrentSchool('students', data.student, currentUser, 'schoolId', { transaction });
|
||||||
await enrollments.setStudent( data.student || null, {
|
await enrollments.setStudent( data.student || null, {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await assertRelatedRecordInCurrentSchool('classes', data.class, currentUser, 'schoolId', { transaction });
|
||||||
await enrollments.setClass( data.class || null, {
|
await enrollments.setClass( data.class || null, {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
@ -91,6 +92,7 @@ module.exports = class EnrollmentsDBApi {
|
|||||||
importHash: item.importHash || null,
|
importHash: item.importHash || null,
|
||||||
createdById: currentUser.id,
|
createdById: currentUser.id,
|
||||||
updatedById: currentUser.id,
|
updatedById: currentUser.id,
|
||||||
|
schoolId: resolveSchoolIdForMutation(item.school, currentUser),
|
||||||
createdAt: new Date(Date.now() + index * 1000),
|
createdAt: new Date(Date.now() + index * 1000),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -106,9 +108,8 @@ module.exports = class EnrollmentsDBApi {
|
|||||||
static async update(id, data, options) {
|
static async update(id, data, options) {
|
||||||
const currentUser = (options && options.currentUser) || {id: null};
|
const currentUser = (options && options.currentUser) || {id: null};
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
const globalAccess = currentUser.app_role?.globalAccess;
|
|
||||||
|
|
||||||
const enrollments = await db.enrollments.findByPk(id, {}, {transaction});
|
const enrollments = await db.enrollments.findByPk(id, {}, {transaction});
|
||||||
|
assertRecordInCurrentSchool(enrollments, currentUser, 'schoolId');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -133,13 +134,14 @@ module.exports = class EnrollmentsDBApi {
|
|||||||
if (data.school !== undefined) {
|
if (data.school !== undefined) {
|
||||||
await enrollments.setSchool(
|
await enrollments.setSchool(
|
||||||
|
|
||||||
data.school,
|
resolveSchoolIdForMutation(data.school, currentUser),
|
||||||
|
|
||||||
{ transaction }
|
{ transaction }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.student !== undefined) {
|
if (data.student !== undefined) {
|
||||||
|
await assertRelatedRecordInCurrentSchool('students', data.student, currentUser, 'schoolId', { transaction });
|
||||||
await enrollments.setStudent(
|
await enrollments.setStudent(
|
||||||
|
|
||||||
data.student,
|
data.student,
|
||||||
@ -149,6 +151,7 @@ module.exports = class EnrollmentsDBApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (data.class !== undefined) {
|
if (data.class !== undefined) {
|
||||||
|
await assertRelatedRecordInCurrentSchool('classes', data.class, currentUser, 'schoolId', { transaction });
|
||||||
await enrollments.setClass(
|
await enrollments.setClass(
|
||||||
|
|
||||||
data.class,
|
data.class,
|
||||||
@ -179,6 +182,8 @@ module.exports = class EnrollmentsDBApi {
|
|||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
enrollments.forEach((record) => assertRecordInCurrentSchool(record, currentUser, 'schoolId'));
|
||||||
|
|
||||||
await db.sequelize.transaction(async (transaction) => {
|
await db.sequelize.transaction(async (transaction) => {
|
||||||
for (const record of enrollments) {
|
for (const record of enrollments) {
|
||||||
await record.update(
|
await record.update(
|
||||||
@ -200,6 +205,7 @@ module.exports = class EnrollmentsDBApi {
|
|||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
|
||||||
const enrollments = await db.enrollments.findByPk(id, options);
|
const enrollments = await db.enrollments.findByPk(id, options);
|
||||||
|
assertRecordInCurrentSchool(enrollments, currentUser, 'schoolId');
|
||||||
|
|
||||||
await enrollments.update({
|
await enrollments.update({
|
||||||
deletedBy: currentUser.id
|
deletedBy: currentUser.id
|
||||||
@ -216,6 +222,9 @@ module.exports = class EnrollmentsDBApi {
|
|||||||
|
|
||||||
static async findBy(where, options) {
|
static async findBy(where, options) {
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
const currentUser = (options && options.currentUser) || null;
|
||||||
|
|
||||||
|
applySchoolScope(where, currentUser?.app_role?.globalAccess, currentUser, 'schoolId');
|
||||||
|
|
||||||
const enrollments = await db.enrollments.findOne(
|
const enrollments = await db.enrollments.findOne(
|
||||||
{ where },
|
{ where },
|
||||||
@ -278,26 +287,11 @@ module.exports = class EnrollmentsDBApi {
|
|||||||
let offset = 0;
|
let offset = 0;
|
||||||
let where = {};
|
let where = {};
|
||||||
const currentPage = +filter.page;
|
const currentPage = +filter.page;
|
||||||
|
|
||||||
|
|
||||||
const user = (options && options.currentUser) || null;
|
const user = (options && options.currentUser) || null;
|
||||||
const userSchools = (user && user.schools?.id) || null;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (userSchools) {
|
|
||||||
if (options?.currentUser?.schoolsId) {
|
|
||||||
where.schoolsId = options.currentUser.schoolsId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
offset = currentPage * limit;
|
offset = currentPage * limit;
|
||||||
|
|
||||||
const orderBy = null;
|
|
||||||
|
|
||||||
const transaction = (options && options.transaction) || undefined;
|
|
||||||
|
|
||||||
let include = [
|
let include = [
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -456,11 +450,7 @@ module.exports = class EnrollmentsDBApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
applySchoolScope(where, globalAccess, user, 'schoolId');
|
||||||
if (globalAccess) {
|
|
||||||
delete where.schoolsId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const queryOptions = {
|
const queryOptions = {
|
||||||
where,
|
where,
|
||||||
@ -491,14 +481,9 @@ module.exports = class EnrollmentsDBApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async findAllAutocomplete(query, limit, offset, globalAccess, organizationId,) {
|
static async findAllAutocomplete(query, limit, offset, globalAccess, schoolId,) {
|
||||||
let where = {};
|
let where = {};
|
||||||
|
|
||||||
|
|
||||||
if (!globalAccess && organizationId) {
|
|
||||||
where.organizationId = organizationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (query) {
|
if (query) {
|
||||||
where = {
|
where = {
|
||||||
@ -513,6 +498,8 @@ module.exports = class EnrollmentsDBApi {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applySchoolScopeById(where, globalAccess, schoolId, 'schoolId');
|
||||||
|
|
||||||
const records = await db.enrollments.findAll({
|
const records = await db.enrollments.findAll({
|
||||||
attributes: [ 'id', 'ano_lectivo' ],
|
attributes: [ 'id', 'ano_lectivo' ],
|
||||||
where,
|
where,
|
||||||
|
|||||||
@ -36,15 +36,17 @@ module.exports = class FileDBApi {
|
|||||||
);
|
);
|
||||||
|
|
||||||
for (const file of inexistentFiles) {
|
for (const file of inexistentFiles) {
|
||||||
|
const safeFile = await services.validateFileMetadata(file, relation, { transaction });
|
||||||
|
|
||||||
await db.file.create(
|
await db.file.create(
|
||||||
{
|
{
|
||||||
belongsTo: relation.belongsTo,
|
belongsTo: relation.belongsTo,
|
||||||
belongsToColumn: relation.belongsToColumn,
|
belongsToColumn: relation.belongsToColumn,
|
||||||
belongsToId: relation.belongsToId,
|
belongsToId: relation.belongsToId,
|
||||||
name: file.name,
|
name: safeFile.name,
|
||||||
sizeInBytes: file.sizeInBytes,
|
sizeInBytes: safeFile.sizeInBytes,
|
||||||
privateUrl: file.privateUrl,
|
privateUrl: safeFile.privateUrl,
|
||||||
publicUrl: file.publicUrl,
|
publicUrl: safeFile.publicUrl,
|
||||||
createdById: currentUser.id,
|
createdById: currentUser.id,
|
||||||
updatedById: currentUser.id,
|
updatedById: currentUser.id,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
|
|
||||||
const db = require('../models');
|
const db = require('../models');
|
||||||
const FileDBApi = require('./file');
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const Utils = require('../utils');
|
const Utils = require('../utils');
|
||||||
|
const { applySchoolScope, applySchoolScopeById, assertRecordInCurrentSchool, resolveSchoolIdForMutation } = require('./schoolScope');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -44,7 +43,7 @@ module.exports = class GradesDBApi {
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
await grades.setSchool( data.school || null, {
|
await grades.setSchool(resolveSchoolIdForMutation(data.school, currentUser), {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -83,6 +82,7 @@ module.exports = class GradesDBApi {
|
|||||||
importHash: item.importHash || null,
|
importHash: item.importHash || null,
|
||||||
createdById: currentUser.id,
|
createdById: currentUser.id,
|
||||||
updatedById: currentUser.id,
|
updatedById: currentUser.id,
|
||||||
|
schoolId: resolveSchoolIdForMutation(item.school, currentUser),
|
||||||
createdAt: new Date(Date.now() + index * 1000),
|
createdAt: new Date(Date.now() + index * 1000),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -98,9 +98,8 @@ module.exports = class GradesDBApi {
|
|||||||
static async update(id, data, options) {
|
static async update(id, data, options) {
|
||||||
const currentUser = (options && options.currentUser) || {id: null};
|
const currentUser = (options && options.currentUser) || {id: null};
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
const globalAccess = currentUser.app_role?.globalAccess;
|
|
||||||
|
|
||||||
const grades = await db.grades.findByPk(id, {}, {transaction});
|
const grades = await db.grades.findByPk(id, {}, {transaction});
|
||||||
|
assertRecordInCurrentSchool(grades, currentUser, 'schoolId');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -125,7 +124,7 @@ module.exports = class GradesDBApi {
|
|||||||
if (data.school !== undefined) {
|
if (data.school !== undefined) {
|
||||||
await grades.setSchool(
|
await grades.setSchool(
|
||||||
|
|
||||||
data.school,
|
resolveSchoolIdForMutation(data.school, currentUser),
|
||||||
|
|
||||||
{ transaction }
|
{ transaction }
|
||||||
);
|
);
|
||||||
@ -153,6 +152,8 @@ module.exports = class GradesDBApi {
|
|||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
grades.forEach((record) => assertRecordInCurrentSchool(record, currentUser, 'schoolId'));
|
||||||
|
|
||||||
await db.sequelize.transaction(async (transaction) => {
|
await db.sequelize.transaction(async (transaction) => {
|
||||||
for (const record of grades) {
|
for (const record of grades) {
|
||||||
await record.update(
|
await record.update(
|
||||||
@ -174,6 +175,7 @@ module.exports = class GradesDBApi {
|
|||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
|
||||||
const grades = await db.grades.findByPk(id, options);
|
const grades = await db.grades.findByPk(id, options);
|
||||||
|
assertRecordInCurrentSchool(grades, currentUser, 'schoolId');
|
||||||
|
|
||||||
await grades.update({
|
await grades.update({
|
||||||
deletedBy: currentUser.id
|
deletedBy: currentUser.id
|
||||||
@ -190,6 +192,9 @@ module.exports = class GradesDBApi {
|
|||||||
|
|
||||||
static async findBy(where, options) {
|
static async findBy(where, options) {
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
const currentUser = (options && options.currentUser) || null;
|
||||||
|
|
||||||
|
applySchoolScope(where, currentUser?.app_role?.globalAccess, currentUser, 'schoolId');
|
||||||
|
|
||||||
const grades = await db.grades.findOne(
|
const grades = await db.grades.findOne(
|
||||||
{ where },
|
{ where },
|
||||||
@ -246,26 +251,11 @@ module.exports = class GradesDBApi {
|
|||||||
let offset = 0;
|
let offset = 0;
|
||||||
let where = {};
|
let where = {};
|
||||||
const currentPage = +filter.page;
|
const currentPage = +filter.page;
|
||||||
|
|
||||||
|
|
||||||
const user = (options && options.currentUser) || null;
|
const user = (options && options.currentUser) || null;
|
||||||
const userSchools = (user && user.schools?.id) || null;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (userSchools) {
|
|
||||||
if (options?.currentUser?.schoolsId) {
|
|
||||||
where.schoolsId = options.currentUser.schoolsId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
offset = currentPage * limit;
|
offset = currentPage * limit;
|
||||||
|
|
||||||
const orderBy = null;
|
|
||||||
|
|
||||||
const transaction = (options && options.transaction) || undefined;
|
|
||||||
|
|
||||||
let include = [
|
let include = [
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -386,11 +376,7 @@ module.exports = class GradesDBApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
applySchoolScope(where, globalAccess, user, 'schoolId');
|
||||||
if (globalAccess) {
|
|
||||||
delete where.schoolsId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const queryOptions = {
|
const queryOptions = {
|
||||||
where,
|
where,
|
||||||
@ -421,14 +407,9 @@ module.exports = class GradesDBApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async findAllAutocomplete(query, limit, offset, globalAccess, organizationId,) {
|
static async findAllAutocomplete(query, limit, offset, globalAccess, schoolId,) {
|
||||||
let where = {};
|
let where = {};
|
||||||
|
|
||||||
|
|
||||||
if (!globalAccess && organizationId) {
|
|
||||||
where.organizationId = organizationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (query) {
|
if (query) {
|
||||||
where = {
|
where = {
|
||||||
@ -443,6 +424,8 @@ module.exports = class GradesDBApi {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applySchoolScopeById(where, globalAccess, schoolId, 'schoolId');
|
||||||
|
|
||||||
const records = await db.grades.findAll({
|
const records = await db.grades.findAll({
|
||||||
attributes: [ 'id', 'nome' ],
|
attributes: [ 'id', 'nome' ],
|
||||||
where,
|
where,
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
|
|
||||||
const db = require('../models');
|
const db = require('../models');
|
||||||
const FileDBApi = require('./file');
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const Utils = require('../utils');
|
const Utils = require('../utils');
|
||||||
|
const { applySchoolScope, applySchoolScopeById, assertRecordInCurrentSchool, resolveSchoolIdForMutation } = require('./schoolScope');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -49,7 +48,7 @@ module.exports = class GuardiansDBApi {
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
await guardians.setSchool( data.school || null, {
|
await guardians.setSchool(resolveSchoolIdForMutation(data.school, currentUser), {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -93,6 +92,7 @@ module.exports = class GuardiansDBApi {
|
|||||||
importHash: item.importHash || null,
|
importHash: item.importHash || null,
|
||||||
createdById: currentUser.id,
|
createdById: currentUser.id,
|
||||||
updatedById: currentUser.id,
|
updatedById: currentUser.id,
|
||||||
|
schoolId: resolveSchoolIdForMutation(item.school, currentUser),
|
||||||
createdAt: new Date(Date.now() + index * 1000),
|
createdAt: new Date(Date.now() + index * 1000),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -108,9 +108,8 @@ module.exports = class GuardiansDBApi {
|
|||||||
static async update(id, data, options) {
|
static async update(id, data, options) {
|
||||||
const currentUser = (options && options.currentUser) || {id: null};
|
const currentUser = (options && options.currentUser) || {id: null};
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
const globalAccess = currentUser.app_role?.globalAccess;
|
|
||||||
|
|
||||||
const guardians = await db.guardians.findByPk(id, {}, {transaction});
|
const guardians = await db.guardians.findByPk(id, {}, {transaction});
|
||||||
|
assertRecordInCurrentSchool(guardians, currentUser, 'schoolId');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -138,7 +137,7 @@ module.exports = class GuardiansDBApi {
|
|||||||
if (data.school !== undefined) {
|
if (data.school !== undefined) {
|
||||||
await guardians.setSchool(
|
await guardians.setSchool(
|
||||||
|
|
||||||
data.school,
|
resolveSchoolIdForMutation(data.school, currentUser),
|
||||||
|
|
||||||
{ transaction }
|
{ transaction }
|
||||||
);
|
);
|
||||||
@ -166,6 +165,8 @@ module.exports = class GuardiansDBApi {
|
|||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
guardians.forEach((record) => assertRecordInCurrentSchool(record, currentUser, 'schoolId'));
|
||||||
|
|
||||||
await db.sequelize.transaction(async (transaction) => {
|
await db.sequelize.transaction(async (transaction) => {
|
||||||
for (const record of guardians) {
|
for (const record of guardians) {
|
||||||
await record.update(
|
await record.update(
|
||||||
@ -187,6 +188,7 @@ module.exports = class GuardiansDBApi {
|
|||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
|
||||||
const guardians = await db.guardians.findByPk(id, options);
|
const guardians = await db.guardians.findByPk(id, options);
|
||||||
|
assertRecordInCurrentSchool(guardians, currentUser, 'schoolId');
|
||||||
|
|
||||||
await guardians.update({
|
await guardians.update({
|
||||||
deletedBy: currentUser.id
|
deletedBy: currentUser.id
|
||||||
@ -203,6 +205,9 @@ module.exports = class GuardiansDBApi {
|
|||||||
|
|
||||||
static async findBy(where, options) {
|
static async findBy(where, options) {
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
const currentUser = (options && options.currentUser) || null;
|
||||||
|
|
||||||
|
applySchoolScope(where, currentUser?.app_role?.globalAccess, currentUser, 'schoolId');
|
||||||
|
|
||||||
const guardians = await db.guardians.findOne(
|
const guardians = await db.guardians.findOne(
|
||||||
{ where },
|
{ where },
|
||||||
@ -259,26 +264,11 @@ module.exports = class GuardiansDBApi {
|
|||||||
let offset = 0;
|
let offset = 0;
|
||||||
let where = {};
|
let where = {};
|
||||||
const currentPage = +filter.page;
|
const currentPage = +filter.page;
|
||||||
|
|
||||||
|
|
||||||
const user = (options && options.currentUser) || null;
|
const user = (options && options.currentUser) || null;
|
||||||
const userSchools = (user && user.schools?.id) || null;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (userSchools) {
|
|
||||||
if (options?.currentUser?.schoolsId) {
|
|
||||||
where.schoolsId = options.currentUser.schoolsId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
offset = currentPage * limit;
|
offset = currentPage * limit;
|
||||||
|
|
||||||
const orderBy = null;
|
|
||||||
|
|
||||||
const transaction = (options && options.transaction) || undefined;
|
|
||||||
|
|
||||||
let include = [
|
let include = [
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -397,11 +387,7 @@ module.exports = class GuardiansDBApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
applySchoolScope(where, globalAccess, user, 'schoolId');
|
||||||
if (globalAccess) {
|
|
||||||
delete where.schoolsId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const queryOptions = {
|
const queryOptions = {
|
||||||
where,
|
where,
|
||||||
@ -432,14 +418,9 @@ module.exports = class GuardiansDBApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async findAllAutocomplete(query, limit, offset, globalAccess, organizationId,) {
|
static async findAllAutocomplete(query, limit, offset, globalAccess, schoolId,) {
|
||||||
let where = {};
|
let where = {};
|
||||||
|
|
||||||
|
|
||||||
if (!globalAccess && organizationId) {
|
|
||||||
where.organizationId = organizationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (query) {
|
if (query) {
|
||||||
where = {
|
where = {
|
||||||
@ -454,6 +435,8 @@ module.exports = class GuardiansDBApi {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applySchoolScopeById(where, globalAccess, schoolId, 'schoolId');
|
||||||
|
|
||||||
const records = await db.guardians.findAll({
|
const records = await db.guardians.findAll({
|
||||||
attributes: [ 'id', 'nome' ],
|
attributes: [ 'id', 'nome' ],
|
||||||
where,
|
where,
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
|
|
||||||
const db = require('../models');
|
const db = require('../models');
|
||||||
const FileDBApi = require('./file');
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const Utils = require('../utils');
|
const Utils = require('../utils');
|
||||||
|
const { applySchoolScope, applySchoolScopeById, assertRecordInCurrentSchool, assertRelatedRecordInCurrentSchool, resolveSchoolIdForMutation } = require('./schoolScope');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -59,10 +58,11 @@ module.exports = class InvoicesDBApi {
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
await invoices.setSchool( data.school || null, {
|
await invoices.setSchool(resolveSchoolIdForMutation(data.school, currentUser), {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await assertRelatedRecordInCurrentSchool('students', data.student, currentUser, 'schoolId', { transaction });
|
||||||
await invoices.setStudent( data.student || null, {
|
await invoices.setStudent( data.student || null, {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
@ -117,6 +117,7 @@ module.exports = class InvoicesDBApi {
|
|||||||
importHash: item.importHash || null,
|
importHash: item.importHash || null,
|
||||||
createdById: currentUser.id,
|
createdById: currentUser.id,
|
||||||
updatedById: currentUser.id,
|
updatedById: currentUser.id,
|
||||||
|
schoolId: resolveSchoolIdForMutation(item.school, currentUser),
|
||||||
createdAt: new Date(Date.now() + index * 1000),
|
createdAt: new Date(Date.now() + index * 1000),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -132,9 +133,8 @@ module.exports = class InvoicesDBApi {
|
|||||||
static async update(id, data, options) {
|
static async update(id, data, options) {
|
||||||
const currentUser = (options && options.currentUser) || {id: null};
|
const currentUser = (options && options.currentUser) || {id: null};
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
const globalAccess = currentUser.app_role?.globalAccess;
|
|
||||||
|
|
||||||
const invoices = await db.invoices.findByPk(id, {}, {transaction});
|
const invoices = await db.invoices.findByPk(id, {}, {transaction});
|
||||||
|
assertRecordInCurrentSchool(invoices, currentUser, 'schoolId');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -168,13 +168,14 @@ module.exports = class InvoicesDBApi {
|
|||||||
if (data.school !== undefined) {
|
if (data.school !== undefined) {
|
||||||
await invoices.setSchool(
|
await invoices.setSchool(
|
||||||
|
|
||||||
data.school,
|
resolveSchoolIdForMutation(data.school, currentUser),
|
||||||
|
|
||||||
{ transaction }
|
{ transaction }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.student !== undefined) {
|
if (data.student !== undefined) {
|
||||||
|
await assertRelatedRecordInCurrentSchool('students', data.student, currentUser, 'schoolId', { transaction });
|
||||||
await invoices.setStudent(
|
await invoices.setStudent(
|
||||||
|
|
||||||
data.student,
|
data.student,
|
||||||
@ -205,6 +206,8 @@ module.exports = class InvoicesDBApi {
|
|||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
invoices.forEach((record) => assertRecordInCurrentSchool(record, currentUser, 'schoolId'));
|
||||||
|
|
||||||
await db.sequelize.transaction(async (transaction) => {
|
await db.sequelize.transaction(async (transaction) => {
|
||||||
for (const record of invoices) {
|
for (const record of invoices) {
|
||||||
await record.update(
|
await record.update(
|
||||||
@ -226,6 +229,7 @@ module.exports = class InvoicesDBApi {
|
|||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
|
||||||
const invoices = await db.invoices.findByPk(id, options);
|
const invoices = await db.invoices.findByPk(id, options);
|
||||||
|
assertRecordInCurrentSchool(invoices, currentUser, 'schoolId');
|
||||||
|
|
||||||
await invoices.update({
|
await invoices.update({
|
||||||
deletedBy: currentUser.id
|
deletedBy: currentUser.id
|
||||||
@ -242,6 +246,9 @@ module.exports = class InvoicesDBApi {
|
|||||||
|
|
||||||
static async findBy(where, options) {
|
static async findBy(where, options) {
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
const currentUser = (options && options.currentUser) || null;
|
||||||
|
|
||||||
|
applySchoolScope(where, currentUser?.app_role?.globalAccess, currentUser, 'schoolId');
|
||||||
|
|
||||||
const invoices = await db.invoices.findOne(
|
const invoices = await db.invoices.findOne(
|
||||||
{ where },
|
{ where },
|
||||||
@ -303,26 +310,11 @@ module.exports = class InvoicesDBApi {
|
|||||||
let offset = 0;
|
let offset = 0;
|
||||||
let where = {};
|
let where = {};
|
||||||
const currentPage = +filter.page;
|
const currentPage = +filter.page;
|
||||||
|
|
||||||
|
|
||||||
const user = (options && options.currentUser) || null;
|
const user = (options && options.currentUser) || null;
|
||||||
const userSchools = (user && user.schools?.id) || null;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (userSchools) {
|
|
||||||
if (options?.currentUser?.schoolsId) {
|
|
||||||
where.schoolsId = options.currentUser.schoolsId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
offset = currentPage * limit;
|
offset = currentPage * limit;
|
||||||
|
|
||||||
const orderBy = null;
|
|
||||||
|
|
||||||
const transaction = (options && options.transaction) || undefined;
|
|
||||||
|
|
||||||
let include = [
|
let include = [
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -521,11 +513,7 @@ module.exports = class InvoicesDBApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
applySchoolScope(where, globalAccess, user, 'schoolId');
|
||||||
if (globalAccess) {
|
|
||||||
delete where.schoolsId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const queryOptions = {
|
const queryOptions = {
|
||||||
where,
|
where,
|
||||||
@ -556,14 +544,9 @@ module.exports = class InvoicesDBApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async findAllAutocomplete(query, limit, offset, globalAccess, organizationId,) {
|
static async findAllAutocomplete(query, limit, offset, globalAccess, schoolId,) {
|
||||||
let where = {};
|
let where = {};
|
||||||
|
|
||||||
|
|
||||||
if (!globalAccess && organizationId) {
|
|
||||||
where.organizationId = organizationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (query) {
|
if (query) {
|
||||||
where = {
|
where = {
|
||||||
@ -578,6 +561,8 @@ module.exports = class InvoicesDBApi {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applySchoolScopeById(where, globalAccess, schoolId, 'schoolId');
|
||||||
|
|
||||||
const records = await db.invoices.findAll({
|
const records = await db.invoices.findAll({
|
||||||
attributes: [ 'id', 'referencia' ],
|
attributes: [ 'id', 'referencia' ],
|
||||||
where,
|
where,
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
const db = require('../models');
|
const db = require('../models');
|
||||||
const FileDBApi = require('./file');
|
const FileDBApi = require('./file');
|
||||||
const crypto = require('crypto');
|
|
||||||
const Utils = require('../utils');
|
const Utils = require('../utils');
|
||||||
|
const { applySchoolScope, applySchoolScopeById, assertRecordInCurrentSchool, assertRelatedRecordInCurrentSchool, resolveSchoolIdForMutation } = require('./schoolScope');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -49,10 +49,11 @@ module.exports = class PaymentsDBApi {
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
await payments.setSchool( data.school || null, {
|
await payments.setSchool(resolveSchoolIdForMutation(data.school, currentUser), {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await assertRelatedRecordInCurrentSchool('invoices', data.invoice, currentUser, 'schoolId', { transaction });
|
||||||
await payments.setInvoice( data.invoice || null, {
|
await payments.setInvoice( data.invoice || null, {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
@ -107,6 +108,7 @@ module.exports = class PaymentsDBApi {
|
|||||||
importHash: item.importHash || null,
|
importHash: item.importHash || null,
|
||||||
createdById: currentUser.id,
|
createdById: currentUser.id,
|
||||||
updatedById: currentUser.id,
|
updatedById: currentUser.id,
|
||||||
|
schoolId: resolveSchoolIdForMutation(item.school, currentUser),
|
||||||
createdAt: new Date(Date.now() + index * 1000),
|
createdAt: new Date(Date.now() + index * 1000),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -134,9 +136,8 @@ module.exports = class PaymentsDBApi {
|
|||||||
static async update(id, data, options) {
|
static async update(id, data, options) {
|
||||||
const currentUser = (options && options.currentUser) || {id: null};
|
const currentUser = (options && options.currentUser) || {id: null};
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
const globalAccess = currentUser.app_role?.globalAccess;
|
|
||||||
|
|
||||||
const payments = await db.payments.findByPk(id, {}, {transaction});
|
const payments = await db.payments.findByPk(id, {}, {transaction});
|
||||||
|
assertRecordInCurrentSchool(payments, currentUser, 'schoolId');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -164,13 +165,14 @@ module.exports = class PaymentsDBApi {
|
|||||||
if (data.school !== undefined) {
|
if (data.school !== undefined) {
|
||||||
await payments.setSchool(
|
await payments.setSchool(
|
||||||
|
|
||||||
data.school,
|
resolveSchoolIdForMutation(data.school, currentUser),
|
||||||
|
|
||||||
{ transaction }
|
{ transaction }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.invoice !== undefined) {
|
if (data.invoice !== undefined) {
|
||||||
|
await assertRelatedRecordInCurrentSchool('invoices', data.invoice, currentUser, 'schoolId', { transaction });
|
||||||
await payments.setInvoice(
|
await payments.setInvoice(
|
||||||
|
|
||||||
data.invoice,
|
data.invoice,
|
||||||
@ -184,15 +186,17 @@ module.exports = class PaymentsDBApi {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
await FileDBApi.replaceRelationFiles(
|
if (data.comprovativo !== undefined) {
|
||||||
{
|
await FileDBApi.replaceRelationFiles(
|
||||||
belongsTo: db.payments.getTableName(),
|
{
|
||||||
belongsToColumn: 'comprovativo',
|
belongsTo: db.payments.getTableName(),
|
||||||
belongsToId: payments.id,
|
belongsToColumn: 'comprovativo',
|
||||||
},
|
belongsToId: payments.id,
|
||||||
data.comprovativo,
|
},
|
||||||
options,
|
data.comprovativo,
|
||||||
);
|
options,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return payments;
|
return payments;
|
||||||
@ -211,6 +215,8 @@ module.exports = class PaymentsDBApi {
|
|||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
payments.forEach((record) => assertRecordInCurrentSchool(record, currentUser, 'schoolId'));
|
||||||
|
|
||||||
await db.sequelize.transaction(async (transaction) => {
|
await db.sequelize.transaction(async (transaction) => {
|
||||||
for (const record of payments) {
|
for (const record of payments) {
|
||||||
await record.update(
|
await record.update(
|
||||||
@ -232,6 +238,7 @@ module.exports = class PaymentsDBApi {
|
|||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
|
||||||
const payments = await db.payments.findByPk(id, options);
|
const payments = await db.payments.findByPk(id, options);
|
||||||
|
assertRecordInCurrentSchool(payments, currentUser, 'schoolId');
|
||||||
|
|
||||||
await payments.update({
|
await payments.update({
|
||||||
deletedBy: currentUser.id
|
deletedBy: currentUser.id
|
||||||
@ -248,6 +255,9 @@ module.exports = class PaymentsDBApi {
|
|||||||
|
|
||||||
static async findBy(where, options) {
|
static async findBy(where, options) {
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
const currentUser = (options && options.currentUser) || null;
|
||||||
|
|
||||||
|
applySchoolScope(where, currentUser?.app_role?.globalAccess, currentUser, 'schoolId');
|
||||||
|
|
||||||
const payments = await db.payments.findOne(
|
const payments = await db.payments.findOne(
|
||||||
{ where },
|
{ where },
|
||||||
@ -310,26 +320,11 @@ module.exports = class PaymentsDBApi {
|
|||||||
let offset = 0;
|
let offset = 0;
|
||||||
let where = {};
|
let where = {};
|
||||||
const currentPage = +filter.page;
|
const currentPage = +filter.page;
|
||||||
|
|
||||||
|
|
||||||
const user = (options && options.currentUser) || null;
|
const user = (options && options.currentUser) || null;
|
||||||
const userSchools = (user && user.schools?.id) || null;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (userSchools) {
|
|
||||||
if (options?.currentUser?.schoolsId) {
|
|
||||||
where.schoolsId = options.currentUser.schoolsId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
offset = currentPage * limit;
|
offset = currentPage * limit;
|
||||||
|
|
||||||
const orderBy = null;
|
|
||||||
|
|
||||||
const transaction = (options && options.transaction) || undefined;
|
|
||||||
|
|
||||||
let include = [
|
let include = [
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -498,11 +493,7 @@ module.exports = class PaymentsDBApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
applySchoolScope(where, globalAccess, user, 'schoolId');
|
||||||
if (globalAccess) {
|
|
||||||
delete where.schoolsId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const queryOptions = {
|
const queryOptions = {
|
||||||
where,
|
where,
|
||||||
@ -533,14 +524,9 @@ module.exports = class PaymentsDBApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async findAllAutocomplete(query, limit, offset, globalAccess, organizationId,) {
|
static async findAllAutocomplete(query, limit, offset, globalAccess, schoolId,) {
|
||||||
let where = {};
|
let where = {};
|
||||||
|
|
||||||
|
|
||||||
if (!globalAccess && organizationId) {
|
|
||||||
where.organizationId = organizationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (query) {
|
if (query) {
|
||||||
where = {
|
where = {
|
||||||
@ -555,6 +541,8 @@ module.exports = class PaymentsDBApi {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applySchoolScopeById(where, globalAccess, schoolId, 'schoolId');
|
||||||
|
|
||||||
const records = await db.payments.findAll({
|
const records = await db.payments.findAll({
|
||||||
attributes: [ 'id', 'referencia_transacao' ],
|
attributes: [ 'id', 'referencia_transacao' ],
|
||||||
where,
|
where,
|
||||||
|
|||||||
@ -1,14 +1,20 @@
|
|||||||
|
|
||||||
const db = require('../models');
|
const db = require('../models');
|
||||||
const FileDBApi = require('./file');
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const Utils = require('../utils');
|
const Utils = require('../utils');
|
||||||
|
const ForbiddenError = require('../../services/notifications/errors/forbidden');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const Sequelize = db.Sequelize;
|
const Sequelize = db.Sequelize;
|
||||||
const Op = Sequelize.Op;
|
const Op = Sequelize.Op;
|
||||||
|
|
||||||
|
|
||||||
|
function assertGlobalAccess(currentUser) {
|
||||||
|
if (!currentUser?.app_role?.globalAccess) {
|
||||||
|
throw new ForbiddenError('auth.forbidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = class PermissionsDBApi {
|
module.exports = class PermissionsDBApi {
|
||||||
|
|
||||||
|
|
||||||
@ -16,6 +22,7 @@ module.exports = class PermissionsDBApi {
|
|||||||
static async create(data, options) {
|
static async create(data, options) {
|
||||||
const currentUser = (options && options.currentUser) || { id: null };
|
const currentUser = (options && options.currentUser) || { id: null };
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
assertGlobalAccess(currentUser);
|
||||||
|
|
||||||
const permissions = await db.permissions.create(
|
const permissions = await db.permissions.create(
|
||||||
{
|
{
|
||||||
@ -46,6 +53,7 @@ module.exports = class PermissionsDBApi {
|
|||||||
static async bulkImport(data, options) {
|
static async bulkImport(data, options) {
|
||||||
const currentUser = (options && options.currentUser) || { id: null };
|
const currentUser = (options && options.currentUser) || { id: null };
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
assertGlobalAccess(currentUser);
|
||||||
|
|
||||||
// Prepare data - wrapping individual data transformations in a map() method
|
// Prepare data - wrapping individual data transformations in a map() method
|
||||||
const permissionsData = data.map((item, index) => ({
|
const permissionsData = data.map((item, index) => ({
|
||||||
@ -74,7 +82,7 @@ module.exports = class PermissionsDBApi {
|
|||||||
static async update(id, data, options) {
|
static async update(id, data, options) {
|
||||||
const currentUser = (options && options.currentUser) || {id: null};
|
const currentUser = (options && options.currentUser) || {id: null};
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
const globalAccess = currentUser.app_role?.globalAccess;
|
assertGlobalAccess(currentUser);
|
||||||
|
|
||||||
const permissions = await db.permissions.findByPk(id, {}, {transaction});
|
const permissions = await db.permissions.findByPk(id, {}, {transaction});
|
||||||
|
|
||||||
@ -104,6 +112,7 @@ module.exports = class PermissionsDBApi {
|
|||||||
static async deleteByIds(ids, options) {
|
static async deleteByIds(ids, options) {
|
||||||
const currentUser = (options && options.currentUser) || { id: null };
|
const currentUser = (options && options.currentUser) || { id: null };
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
assertGlobalAccess(currentUser);
|
||||||
|
|
||||||
const permissions = await db.permissions.findAll({
|
const permissions = await db.permissions.findAll({
|
||||||
where: {
|
where: {
|
||||||
@ -133,6 +142,7 @@ module.exports = class PermissionsDBApi {
|
|||||||
static async remove(id, options) {
|
static async remove(id, options) {
|
||||||
const currentUser = (options && options.currentUser) || {id: null};
|
const currentUser = (options && options.currentUser) || {id: null};
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
assertGlobalAccess(currentUser);
|
||||||
|
|
||||||
const permissions = await db.permissions.findByPk(id, options);
|
const permissions = await db.permissions.findByPk(id, options);
|
||||||
|
|
||||||
@ -200,18 +210,12 @@ module.exports = class PermissionsDBApi {
|
|||||||
const currentPage = +filter.page;
|
const currentPage = +filter.page;
|
||||||
|
|
||||||
|
|
||||||
const user = (options && options.currentUser) || null;
|
|
||||||
const userSchools = (user && user.schools?.id) || null;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
offset = currentPage * limit;
|
offset = currentPage * limit;
|
||||||
|
|
||||||
const orderBy = null;
|
|
||||||
|
|
||||||
const transaction = (options && options.transaction) || undefined;
|
|
||||||
|
|
||||||
let include = [
|
let include = [
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
|
|
||||||
const db = require('../models');
|
const db = require('../models');
|
||||||
const FileDBApi = require('./file');
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const Utils = require('../utils');
|
const Utils = require('../utils');
|
||||||
|
const { applySchoolScope, applySchoolScopeById, assertRecordInCurrentSchool, resolveSchoolIdForMutation } = require('./schoolScope');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -54,7 +53,7 @@ module.exports = class ProductsDBApi {
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
await products.setSchool( data.school || null, {
|
await products.setSchool(resolveSchoolIdForMutation(data.school, currentUser), {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -103,6 +102,7 @@ module.exports = class ProductsDBApi {
|
|||||||
importHash: item.importHash || null,
|
importHash: item.importHash || null,
|
||||||
createdById: currentUser.id,
|
createdById: currentUser.id,
|
||||||
updatedById: currentUser.id,
|
updatedById: currentUser.id,
|
||||||
|
schoolId: resolveSchoolIdForMutation(item.school, currentUser),
|
||||||
createdAt: new Date(Date.now() + index * 1000),
|
createdAt: new Date(Date.now() + index * 1000),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -118,9 +118,8 @@ module.exports = class ProductsDBApi {
|
|||||||
static async update(id, data, options) {
|
static async update(id, data, options) {
|
||||||
const currentUser = (options && options.currentUser) || {id: null};
|
const currentUser = (options && options.currentUser) || {id: null};
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
const globalAccess = currentUser.app_role?.globalAccess;
|
|
||||||
|
|
||||||
const products = await db.products.findByPk(id, {}, {transaction});
|
const products = await db.products.findByPk(id, {}, {transaction});
|
||||||
|
assertRecordInCurrentSchool(products, currentUser, 'schoolId');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -151,7 +150,7 @@ module.exports = class ProductsDBApi {
|
|||||||
if (data.school !== undefined) {
|
if (data.school !== undefined) {
|
||||||
await products.setSchool(
|
await products.setSchool(
|
||||||
|
|
||||||
data.school,
|
resolveSchoolIdForMutation(data.school, currentUser),
|
||||||
|
|
||||||
{ transaction }
|
{ transaction }
|
||||||
);
|
);
|
||||||
@ -179,6 +178,8 @@ module.exports = class ProductsDBApi {
|
|||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
products.forEach((record) => assertRecordInCurrentSchool(record, currentUser, 'schoolId'));
|
||||||
|
|
||||||
await db.sequelize.transaction(async (transaction) => {
|
await db.sequelize.transaction(async (transaction) => {
|
||||||
for (const record of products) {
|
for (const record of products) {
|
||||||
await record.update(
|
await record.update(
|
||||||
@ -200,6 +201,7 @@ module.exports = class ProductsDBApi {
|
|||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
|
||||||
const products = await db.products.findByPk(id, options);
|
const products = await db.products.findByPk(id, options);
|
||||||
|
assertRecordInCurrentSchool(products, currentUser, 'schoolId');
|
||||||
|
|
||||||
await products.update({
|
await products.update({
|
||||||
deletedBy: currentUser.id
|
deletedBy: currentUser.id
|
||||||
@ -216,6 +218,9 @@ module.exports = class ProductsDBApi {
|
|||||||
|
|
||||||
static async findBy(where, options) {
|
static async findBy(where, options) {
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
const currentUser = (options && options.currentUser) || null;
|
||||||
|
|
||||||
|
applySchoolScope(where, currentUser?.app_role?.globalAccess, currentUser, 'schoolId');
|
||||||
|
|
||||||
const products = await db.products.findOne(
|
const products = await db.products.findOne(
|
||||||
{ where },
|
{ where },
|
||||||
@ -268,26 +273,11 @@ module.exports = class ProductsDBApi {
|
|||||||
let offset = 0;
|
let offset = 0;
|
||||||
let where = {};
|
let where = {};
|
||||||
const currentPage = +filter.page;
|
const currentPage = +filter.page;
|
||||||
|
|
||||||
|
|
||||||
const user = (options && options.currentUser) || null;
|
const user = (options && options.currentUser) || null;
|
||||||
const userSchools = (user && user.schools?.id) || null;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (userSchools) {
|
|
||||||
if (options?.currentUser?.schoolsId) {
|
|
||||||
where.schoolsId = options.currentUser.schoolsId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
offset = currentPage * limit;
|
offset = currentPage * limit;
|
||||||
|
|
||||||
const orderBy = null;
|
|
||||||
|
|
||||||
const transaction = (options && options.transaction) || undefined;
|
|
||||||
|
|
||||||
let include = [
|
let include = [
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -456,11 +446,7 @@ module.exports = class ProductsDBApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
applySchoolScope(where, globalAccess, user, 'schoolId');
|
||||||
if (globalAccess) {
|
|
||||||
delete where.schoolsId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const queryOptions = {
|
const queryOptions = {
|
||||||
where,
|
where,
|
||||||
@ -491,14 +477,9 @@ module.exports = class ProductsDBApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async findAllAutocomplete(query, limit, offset, globalAccess, organizationId,) {
|
static async findAllAutocomplete(query, limit, offset, globalAccess, schoolId,) {
|
||||||
let where = {};
|
let where = {};
|
||||||
|
|
||||||
|
|
||||||
if (!globalAccess && organizationId) {
|
|
||||||
where.organizationId = organizationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (query) {
|
if (query) {
|
||||||
where = {
|
where = {
|
||||||
@ -513,6 +494,8 @@ module.exports = class ProductsDBApi {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applySchoolScopeById(where, globalAccess, schoolId, 'schoolId');
|
||||||
|
|
||||||
const records = await db.products.findAll({
|
const records = await db.products.findAll({
|
||||||
attributes: [ 'id', 'nome' ],
|
attributes: [ 'id', 'nome' ],
|
||||||
where,
|
where,
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
|
|
||||||
const db = require('../models');
|
const db = require('../models');
|
||||||
const FileDBApi = require('./file');
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const Utils = require('../utils');
|
const Utils = require('../utils');
|
||||||
|
const ForbiddenError = require('../../services/notifications/errors/forbidden');
|
||||||
|
|
||||||
|
|
||||||
const config = require('../../config');
|
const config = require('../../config');
|
||||||
@ -11,6 +10,13 @@ const config = require('../../config');
|
|||||||
const Sequelize = db.Sequelize;
|
const Sequelize = db.Sequelize;
|
||||||
const Op = Sequelize.Op;
|
const Op = Sequelize.Op;
|
||||||
|
|
||||||
|
|
||||||
|
function assertGlobalAccess(currentUser) {
|
||||||
|
if (!currentUser?.app_role?.globalAccess) {
|
||||||
|
throw new ForbiddenError('auth.forbidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = class RolesDBApi {
|
module.exports = class RolesDBApi {
|
||||||
|
|
||||||
|
|
||||||
@ -18,6 +24,7 @@ module.exports = class RolesDBApi {
|
|||||||
static async create(data, options) {
|
static async create(data, options) {
|
||||||
const currentUser = (options && options.currentUser) || { id: null };
|
const currentUser = (options && options.currentUser) || { id: null };
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
assertGlobalAccess(currentUser);
|
||||||
|
|
||||||
const roles = await db.roles.create(
|
const roles = await db.roles.create(
|
||||||
{
|
{
|
||||||
@ -63,6 +70,7 @@ module.exports = class RolesDBApi {
|
|||||||
static async bulkImport(data, options) {
|
static async bulkImport(data, options) {
|
||||||
const currentUser = (options && options.currentUser) || { id: null };
|
const currentUser = (options && options.currentUser) || { id: null };
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
assertGlobalAccess(currentUser);
|
||||||
|
|
||||||
// Prepare data - wrapping individual data transformations in a map() method
|
// Prepare data - wrapping individual data transformations in a map() method
|
||||||
const rolesData = data.map((item, index) => ({
|
const rolesData = data.map((item, index) => ({
|
||||||
@ -102,7 +110,7 @@ module.exports = class RolesDBApi {
|
|||||||
static async update(id, data, options) {
|
static async update(id, data, options) {
|
||||||
const currentUser = (options && options.currentUser) || {id: null};
|
const currentUser = (options && options.currentUser) || {id: null};
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
const globalAccess = currentUser.app_role?.globalAccess;
|
assertGlobalAccess(currentUser);
|
||||||
|
|
||||||
const roles = await db.roles.findByPk(id, {}, {transaction});
|
const roles = await db.roles.findByPk(id, {}, {transaction});
|
||||||
|
|
||||||
@ -142,6 +150,7 @@ module.exports = class RolesDBApi {
|
|||||||
static async deleteByIds(ids, options) {
|
static async deleteByIds(ids, options) {
|
||||||
const currentUser = (options && options.currentUser) || { id: null };
|
const currentUser = (options && options.currentUser) || { id: null };
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
assertGlobalAccess(currentUser);
|
||||||
|
|
||||||
const roles = await db.roles.findAll({
|
const roles = await db.roles.findAll({
|
||||||
where: {
|
where: {
|
||||||
@ -171,6 +180,7 @@ module.exports = class RolesDBApi {
|
|||||||
static async remove(id, options) {
|
static async remove(id, options) {
|
||||||
const currentUser = (options && options.currentUser) || {id: null};
|
const currentUser = (options && options.currentUser) || {id: null};
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
assertGlobalAccess(currentUser);
|
||||||
|
|
||||||
const roles = await db.roles.findByPk(id, options);
|
const roles = await db.roles.findByPk(id, options);
|
||||||
|
|
||||||
@ -247,18 +257,12 @@ module.exports = class RolesDBApi {
|
|||||||
const currentPage = +filter.page;
|
const currentPage = +filter.page;
|
||||||
|
|
||||||
|
|
||||||
const user = (options && options.currentUser) || null;
|
|
||||||
const userSchools = (user && user.schools?.id) || null;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
offset = currentPage * limit;
|
offset = currentPage * limit;
|
||||||
|
|
||||||
const orderBy = null;
|
|
||||||
|
|
||||||
const transaction = (options && options.transaction) || undefined;
|
|
||||||
|
|
||||||
let include = [
|
let include = [
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
103
backend/src/db/api/schoolScope.js
Normal file
103
backend/src/db/api/schoolScope.js
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
const ForbiddenError = require('../../services/notifications/errors/forbidden');
|
||||||
|
const db = require('../models');
|
||||||
|
|
||||||
|
function getCurrentUserSchoolId(currentUser) {
|
||||||
|
return currentUser?.schoolsId || currentUser?.schools?.id || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function applySchoolScopeById(where, globalAccess, schoolId, field = 'schoolId') {
|
||||||
|
if (globalAccess) {
|
||||||
|
return where;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!schoolId) {
|
||||||
|
where.id = null;
|
||||||
|
return where;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field === 'id' && where.id && String(where.id) !== String(schoolId)) {
|
||||||
|
where.id = null;
|
||||||
|
return where;
|
||||||
|
}
|
||||||
|
|
||||||
|
where[field] = schoolId;
|
||||||
|
return where;
|
||||||
|
}
|
||||||
|
|
||||||
|
function applySchoolScope(where, globalAccess, currentUser, field = 'schoolId') {
|
||||||
|
if (!currentUser || globalAccess) {
|
||||||
|
return where;
|
||||||
|
}
|
||||||
|
|
||||||
|
return applySchoolScopeById(where, false, getCurrentUserSchoolId(currentUser), field);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function resolveSchoolIdForMutation(inputSchoolId, currentUser) {
|
||||||
|
if (!currentUser || currentUser?.app_role?.globalAccess) {
|
||||||
|
return inputSchoolId || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const schoolId = getCurrentUserSchoolId(currentUser);
|
||||||
|
if (!schoolId) {
|
||||||
|
throw new ForbiddenError('auth.forbidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
return schoolId;
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertRecordInCurrentSchool(record, currentUser, field = 'schoolId') {
|
||||||
|
if (!record || !currentUser || currentUser?.app_role?.globalAccess) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const schoolId = getCurrentUserSchoolId(currentUser);
|
||||||
|
const recordSchoolId = field === 'id' ? record.id : record[field];
|
||||||
|
|
||||||
|
if (!schoolId || String(recordSchoolId || '') !== String(schoolId)) {
|
||||||
|
throw new ForbiddenError('auth.forbidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function assertRelatedRecordInCurrentSchool(modelName, id, currentUser, field = 'schoolId', options = {}) {
|
||||||
|
if (!id || !currentUser || currentUser?.app_role?.globalAccess) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const model = db[modelName];
|
||||||
|
if (!model) {
|
||||||
|
throw new Error(`School scope model not found: ${modelName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field === 'id') {
|
||||||
|
const schoolId = getCurrentUserSchoolId(currentUser);
|
||||||
|
if (!schoolId || String(id) !== String(schoolId)) {
|
||||||
|
throw new ForbiddenError('auth.forbidden');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!model.rawAttributes?.[field]) {
|
||||||
|
throw new Error(`School scope field ${field} not found on model ${modelName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const record = await model.findByPk(id, {
|
||||||
|
attributes: ['id', field],
|
||||||
|
transaction: options.transaction,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!record) {
|
||||||
|
throw new ForbiddenError('auth.forbidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
assertRecordInCurrentSchool(record, currentUser, field);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
applySchoolScope,
|
||||||
|
applySchoolScopeById,
|
||||||
|
assertRecordInCurrentSchool,
|
||||||
|
assertRelatedRecordInCurrentSchool,
|
||||||
|
resolveSchoolIdForMutation,
|
||||||
|
getCurrentUserSchoolId,
|
||||||
|
};
|
||||||
@ -1,8 +1,7 @@
|
|||||||
|
|
||||||
const db = require('../models');
|
const db = require('../models');
|
||||||
const FileDBApi = require('./file');
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const Utils = require('../utils');
|
const Utils = require('../utils');
|
||||||
|
const { applySchoolScope, applySchoolScopeById, assertRecordInCurrentSchool } = require('./schoolScope');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -25,6 +24,14 @@ module.exports = class SchoolsDBApi {
|
|||||||
||
|
||
|
||||||
null
|
null
|
||||||
,
|
,
|
||||||
|
nif: data.nif || null,
|
||||||
|
phone: data.phone || null,
|
||||||
|
email: data.email || null,
|
||||||
|
province: data.province || null,
|
||||||
|
municipality: data.municipality || null,
|
||||||
|
address: data.address || null,
|
||||||
|
logoUrl: data.logoUrl || null,
|
||||||
|
status: data.status || 'active',
|
||||||
|
|
||||||
importHash: data.importHash || null,
|
importHash: data.importHash || null,
|
||||||
createdById: currentUser.id,
|
createdById: currentUser.id,
|
||||||
@ -55,6 +62,14 @@ module.exports = class SchoolsDBApi {
|
|||||||
||
|
||
|
||||||
null
|
null
|
||||||
,
|
,
|
||||||
|
nif: item.nif || null,
|
||||||
|
phone: item.phone || null,
|
||||||
|
email: item.email || null,
|
||||||
|
province: item.province || null,
|
||||||
|
municipality: item.municipality || null,
|
||||||
|
address: item.address || null,
|
||||||
|
logoUrl: item.logoUrl || null,
|
||||||
|
status: item.status || 'active',
|
||||||
|
|
||||||
importHash: item.importHash || null,
|
importHash: item.importHash || null,
|
||||||
createdById: currentUser.id,
|
createdById: currentUser.id,
|
||||||
@ -74,9 +89,8 @@ module.exports = class SchoolsDBApi {
|
|||||||
static async update(id, data, options) {
|
static async update(id, data, options) {
|
||||||
const currentUser = (options && options.currentUser) || {id: null};
|
const currentUser = (options && options.currentUser) || {id: null};
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
const globalAccess = currentUser.app_role?.globalAccess;
|
|
||||||
|
|
||||||
const schools = await db.schools.findByPk(id, {}, {transaction});
|
const schools = await db.schools.findByPk(id, {}, {transaction});
|
||||||
|
assertRecordInCurrentSchool(schools, currentUser, 'id');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -84,6 +98,14 @@ module.exports = class SchoolsDBApi {
|
|||||||
const updatePayload = {};
|
const updatePayload = {};
|
||||||
|
|
||||||
if (data.name !== undefined) updatePayload.name = data.name;
|
if (data.name !== undefined) updatePayload.name = data.name;
|
||||||
|
if (data.nif !== undefined) updatePayload.nif = data.nif;
|
||||||
|
if (data.phone !== undefined) updatePayload.phone = data.phone;
|
||||||
|
if (data.email !== undefined) updatePayload.email = data.email;
|
||||||
|
if (data.province !== undefined) updatePayload.province = data.province;
|
||||||
|
if (data.municipality !== undefined) updatePayload.municipality = data.municipality;
|
||||||
|
if (data.address !== undefined) updatePayload.address = data.address;
|
||||||
|
if (data.logoUrl !== undefined) updatePayload.logoUrl = data.logoUrl;
|
||||||
|
if (data.status !== undefined) updatePayload.status = data.status;
|
||||||
|
|
||||||
|
|
||||||
updatePayload.updatedById = currentUser.id;
|
updatePayload.updatedById = currentUser.id;
|
||||||
@ -114,6 +136,8 @@ module.exports = class SchoolsDBApi {
|
|||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
schools.forEach((record) => assertRecordInCurrentSchool(record, currentUser, 'id'));
|
||||||
|
|
||||||
await db.sequelize.transaction(async (transaction) => {
|
await db.sequelize.transaction(async (transaction) => {
|
||||||
for (const record of schools) {
|
for (const record of schools) {
|
||||||
await record.update(
|
await record.update(
|
||||||
@ -135,6 +159,7 @@ module.exports = class SchoolsDBApi {
|
|||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
|
||||||
const schools = await db.schools.findByPk(id, options);
|
const schools = await db.schools.findByPk(id, options);
|
||||||
|
assertRecordInCurrentSchool(schools, currentUser, 'id');
|
||||||
|
|
||||||
await schools.update({
|
await schools.update({
|
||||||
deletedBy: currentUser.id
|
deletedBy: currentUser.id
|
||||||
@ -151,6 +176,9 @@ module.exports = class SchoolsDBApi {
|
|||||||
|
|
||||||
static async findBy(where, options) {
|
static async findBy(where, options) {
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
const currentUser = (options && options.currentUser) || null;
|
||||||
|
|
||||||
|
applySchoolScope(where, currentUser?.app_role?.globalAccess, currentUser, 'id');
|
||||||
|
|
||||||
const schools = await db.schools.findOne(
|
const schools = await db.schools.findOne(
|
||||||
{ where },
|
{ where },
|
||||||
@ -270,26 +298,11 @@ module.exports = class SchoolsDBApi {
|
|||||||
let offset = 0;
|
let offset = 0;
|
||||||
let where = {};
|
let where = {};
|
||||||
const currentPage = +filter.page;
|
const currentPage = +filter.page;
|
||||||
|
|
||||||
|
|
||||||
const user = (options && options.currentUser) || null;
|
const user = (options && options.currentUser) || null;
|
||||||
const userSchools = (user && user.schools?.id) || null;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (userSchools) {
|
|
||||||
if (options?.currentUser?.schoolsId) {
|
|
||||||
where.schoolsId = options.currentUser.schoolsId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
offset = currentPage * limit;
|
offset = currentPage * limit;
|
||||||
|
|
||||||
const orderBy = null;
|
|
||||||
|
|
||||||
const transaction = (options && options.transaction) || undefined;
|
|
||||||
|
|
||||||
let include = [
|
let include = [
|
||||||
|
|
||||||
|
|
||||||
@ -316,6 +329,24 @@ module.exports = class SchoolsDBApi {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (filter.status) {
|
||||||
|
where = {
|
||||||
|
...where,
|
||||||
|
status: filter.status,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter.province) {
|
||||||
|
where = {
|
||||||
|
...where,
|
||||||
|
[Op.and]: Utils.ilike(
|
||||||
|
'schools',
|
||||||
|
'province',
|
||||||
|
filter.province,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -360,11 +391,7 @@ module.exports = class SchoolsDBApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
applySchoolScope(where, globalAccess, user, 'id');
|
||||||
if (globalAccess) {
|
|
||||||
delete where.schoolsId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const queryOptions = {
|
const queryOptions = {
|
||||||
where,
|
where,
|
||||||
@ -395,14 +422,9 @@ module.exports = class SchoolsDBApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async findAllAutocomplete(query, limit, offset, globalAccess, organizationId,) {
|
static async findAllAutocomplete(query, limit, offset, globalAccess, schoolId,) {
|
||||||
let where = {};
|
let where = {};
|
||||||
|
|
||||||
|
|
||||||
if (!globalAccess && organizationId) {
|
|
||||||
where.organizationId = organizationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (query) {
|
if (query) {
|
||||||
where = {
|
where = {
|
||||||
@ -417,6 +439,8 @@ module.exports = class SchoolsDBApi {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applySchoolScopeById(where, globalAccess, schoolId, 'id');
|
||||||
|
|
||||||
const records = await db.schools.findAll({
|
const records = await db.schools.findAll({
|
||||||
attributes: [ 'id', 'name' ],
|
attributes: [ 'id', 'name' ],
|
||||||
where,
|
where,
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
|
|
||||||
const db = require('../models');
|
const db = require('../models');
|
||||||
const FileDBApi = require('./file');
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const Utils = require('../utils');
|
const Utils = require('../utils');
|
||||||
|
const { applySchoolScope, applySchoolScopeById, assertRecordInCurrentSchool, assertRelatedRecordInCurrentSchool, resolveSchoolIdForMutation } = require('./schoolScope');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -40,15 +39,17 @@ module.exports = class Student_guardiansDBApi {
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
await assertRelatedRecordInCurrentSchool('students', data.student, currentUser, 'schoolId', { transaction });
|
||||||
await student_guardians.setStudent( data.student || null, {
|
await student_guardians.setStudent( data.student || null, {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await assertRelatedRecordInCurrentSchool('guardians', data.guardian, currentUser, 'schoolId', { transaction });
|
||||||
await student_guardians.setGuardian( data.guardian || null, {
|
await student_guardians.setGuardian( data.guardian || null, {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
await student_guardians.setSchools( data.schools || null, {
|
await student_guardians.setSchools(resolveSchoolIdForMutation(data.schools, currentUser), {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -83,6 +84,7 @@ module.exports = class Student_guardiansDBApi {
|
|||||||
importHash: item.importHash || null,
|
importHash: item.importHash || null,
|
||||||
createdById: currentUser.id,
|
createdById: currentUser.id,
|
||||||
updatedById: currentUser.id,
|
updatedById: currentUser.id,
|
||||||
|
schoolsId: resolveSchoolIdForMutation(item.schools, currentUser),
|
||||||
createdAt: new Date(Date.now() + index * 1000),
|
createdAt: new Date(Date.now() + index * 1000),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -98,9 +100,8 @@ module.exports = class Student_guardiansDBApi {
|
|||||||
static async update(id, data, options) {
|
static async update(id, data, options) {
|
||||||
const currentUser = (options && options.currentUser) || {id: null};
|
const currentUser = (options && options.currentUser) || {id: null};
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
const globalAccess = currentUser.app_role?.globalAccess;
|
|
||||||
|
|
||||||
const student_guardians = await db.student_guardians.findByPk(id, {}, {transaction});
|
const student_guardians = await db.student_guardians.findByPk(id, {}, {transaction});
|
||||||
|
assertRecordInCurrentSchool(student_guardians, currentUser, 'schoolsId');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -120,6 +121,7 @@ module.exports = class Student_guardiansDBApi {
|
|||||||
|
|
||||||
|
|
||||||
if (data.student !== undefined) {
|
if (data.student !== undefined) {
|
||||||
|
await assertRelatedRecordInCurrentSchool('students', data.student, currentUser, 'schoolId', { transaction });
|
||||||
await student_guardians.setStudent(
|
await student_guardians.setStudent(
|
||||||
|
|
||||||
data.student,
|
data.student,
|
||||||
@ -129,6 +131,7 @@ module.exports = class Student_guardiansDBApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (data.guardian !== undefined) {
|
if (data.guardian !== undefined) {
|
||||||
|
await assertRelatedRecordInCurrentSchool('guardians', data.guardian, currentUser, 'schoolId', { transaction });
|
||||||
await student_guardians.setGuardian(
|
await student_guardians.setGuardian(
|
||||||
|
|
||||||
data.guardian,
|
data.guardian,
|
||||||
@ -140,7 +143,7 @@ module.exports = class Student_guardiansDBApi {
|
|||||||
if (data.schools !== undefined) {
|
if (data.schools !== undefined) {
|
||||||
await student_guardians.setSchools(
|
await student_guardians.setSchools(
|
||||||
|
|
||||||
data.schools,
|
resolveSchoolIdForMutation(data.schools, currentUser),
|
||||||
|
|
||||||
{ transaction }
|
{ transaction }
|
||||||
);
|
);
|
||||||
@ -168,6 +171,8 @@ module.exports = class Student_guardiansDBApi {
|
|||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
student_guardians.forEach((record) => assertRecordInCurrentSchool(record, currentUser, 'schoolsId'));
|
||||||
|
|
||||||
await db.sequelize.transaction(async (transaction) => {
|
await db.sequelize.transaction(async (transaction) => {
|
||||||
for (const record of student_guardians) {
|
for (const record of student_guardians) {
|
||||||
await record.update(
|
await record.update(
|
||||||
@ -189,6 +194,7 @@ module.exports = class Student_guardiansDBApi {
|
|||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
|
||||||
const student_guardians = await db.student_guardians.findByPk(id, options);
|
const student_guardians = await db.student_guardians.findByPk(id, options);
|
||||||
|
assertRecordInCurrentSchool(student_guardians, currentUser, 'schoolsId');
|
||||||
|
|
||||||
await student_guardians.update({
|
await student_guardians.update({
|
||||||
deletedBy: currentUser.id
|
deletedBy: currentUser.id
|
||||||
@ -205,6 +211,9 @@ module.exports = class Student_guardiansDBApi {
|
|||||||
|
|
||||||
static async findBy(where, options) {
|
static async findBy(where, options) {
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
const currentUser = (options && options.currentUser) || null;
|
||||||
|
|
||||||
|
applySchoolScope(where, currentUser?.app_role?.globalAccess, currentUser, 'schoolsId');
|
||||||
|
|
||||||
const student_guardians = await db.student_guardians.findOne(
|
const student_guardians = await db.student_guardians.findOne(
|
||||||
{ where },
|
{ where },
|
||||||
@ -267,26 +276,11 @@ module.exports = class Student_guardiansDBApi {
|
|||||||
let offset = 0;
|
let offset = 0;
|
||||||
let where = {};
|
let where = {};
|
||||||
const currentPage = +filter.page;
|
const currentPage = +filter.page;
|
||||||
|
|
||||||
|
|
||||||
const user = (options && options.currentUser) || null;
|
const user = (options && options.currentUser) || null;
|
||||||
const userSchools = (user && user.schools?.id) || null;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (userSchools) {
|
|
||||||
if (options?.currentUser?.schoolsId) {
|
|
||||||
where.schoolsId = options.currentUser.schoolsId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
offset = currentPage * limit;
|
offset = currentPage * limit;
|
||||||
|
|
||||||
const orderBy = null;
|
|
||||||
|
|
||||||
const transaction = (options && options.transaction) || undefined;
|
|
||||||
|
|
||||||
let include = [
|
let include = [
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -417,11 +411,7 @@ module.exports = class Student_guardiansDBApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
applySchoolScope(where, globalAccess, user, 'schoolsId');
|
||||||
if (globalAccess) {
|
|
||||||
delete where.schoolsId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const queryOptions = {
|
const queryOptions = {
|
||||||
where,
|
where,
|
||||||
@ -452,14 +442,9 @@ module.exports = class Student_guardiansDBApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async findAllAutocomplete(query, limit, offset, globalAccess, organizationId,) {
|
static async findAllAutocomplete(query, limit, offset, globalAccess, schoolId,) {
|
||||||
let where = {};
|
let where = {};
|
||||||
|
|
||||||
|
|
||||||
if (!globalAccess && organizationId) {
|
|
||||||
where.organizationId = organizationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (query) {
|
if (query) {
|
||||||
where = {
|
where = {
|
||||||
@ -474,6 +459,8 @@ module.exports = class Student_guardiansDBApi {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applySchoolScopeById(where, globalAccess, schoolId, 'schoolsId');
|
||||||
|
|
||||||
const records = await db.student_guardians.findAll({
|
const records = await db.student_guardians.findAll({
|
||||||
attributes: [ 'id', 'tipo_responsabilidade' ],
|
attributes: [ 'id', 'tipo_responsabilidade' ],
|
||||||
where,
|
where,
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
const db = require('../models');
|
const db = require('../models');
|
||||||
const FileDBApi = require('./file');
|
const FileDBApi = require('./file');
|
||||||
const crypto = require('crypto');
|
|
||||||
const Utils = require('../utils');
|
const Utils = require('../utils');
|
||||||
|
const { applySchoolScope, applySchoolScopeById, assertRecordInCurrentSchool, resolveSchoolIdForMutation } = require('./schoolScope');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ module.exports = class StudentsDBApi {
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
await students.setSchool( data.school || null, {
|
await students.setSchool(resolveSchoolIdForMutation(data.school, currentUser), {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -153,6 +153,7 @@ module.exports = class StudentsDBApi {
|
|||||||
importHash: item.importHash || null,
|
importHash: item.importHash || null,
|
||||||
createdById: currentUser.id,
|
createdById: currentUser.id,
|
||||||
updatedById: currentUser.id,
|
updatedById: currentUser.id,
|
||||||
|
schoolId: resolveSchoolIdForMutation(item.school, currentUser),
|
||||||
createdAt: new Date(Date.now() + index * 1000),
|
createdAt: new Date(Date.now() + index * 1000),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -180,9 +181,8 @@ module.exports = class StudentsDBApi {
|
|||||||
static async update(id, data, options) {
|
static async update(id, data, options) {
|
||||||
const currentUser = (options && options.currentUser) || {id: null};
|
const currentUser = (options && options.currentUser) || {id: null};
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
const globalAccess = currentUser.app_role?.globalAccess;
|
|
||||||
|
|
||||||
const students = await db.students.findByPk(id, {}, {transaction});
|
const students = await db.students.findByPk(id, {}, {transaction});
|
||||||
|
assertRecordInCurrentSchool(students, currentUser, 'schoolId');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -225,7 +225,7 @@ module.exports = class StudentsDBApi {
|
|||||||
if (data.school !== undefined) {
|
if (data.school !== undefined) {
|
||||||
await students.setSchool(
|
await students.setSchool(
|
||||||
|
|
||||||
data.school,
|
resolveSchoolIdForMutation(data.school, currentUser),
|
||||||
|
|
||||||
{ transaction }
|
{ transaction }
|
||||||
);
|
);
|
||||||
@ -236,15 +236,17 @@ module.exports = class StudentsDBApi {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
await FileDBApi.replaceRelationFiles(
|
if (data.foto !== undefined) {
|
||||||
{
|
await FileDBApi.replaceRelationFiles(
|
||||||
belongsTo: db.students.getTableName(),
|
{
|
||||||
belongsToColumn: 'foto',
|
belongsTo: db.students.getTableName(),
|
||||||
belongsToId: students.id,
|
belongsToColumn: 'foto',
|
||||||
},
|
belongsToId: students.id,
|
||||||
data.foto,
|
},
|
||||||
options,
|
data.foto,
|
||||||
);
|
options,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return students;
|
return students;
|
||||||
@ -263,6 +265,8 @@ module.exports = class StudentsDBApi {
|
|||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
students.forEach((record) => assertRecordInCurrentSchool(record, currentUser, 'schoolId'));
|
||||||
|
|
||||||
await db.sequelize.transaction(async (transaction) => {
|
await db.sequelize.transaction(async (transaction) => {
|
||||||
for (const record of students) {
|
for (const record of students) {
|
||||||
await record.update(
|
await record.update(
|
||||||
@ -284,6 +288,7 @@ module.exports = class StudentsDBApi {
|
|||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
|
||||||
const students = await db.students.findByPk(id, options);
|
const students = await db.students.findByPk(id, options);
|
||||||
|
assertRecordInCurrentSchool(students, currentUser, 'schoolId');
|
||||||
|
|
||||||
await students.update({
|
await students.update({
|
||||||
deletedBy: currentUser.id
|
deletedBy: currentUser.id
|
||||||
@ -300,6 +305,9 @@ module.exports = class StudentsDBApi {
|
|||||||
|
|
||||||
static async findBy(where, options) {
|
static async findBy(where, options) {
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
const currentUser = (options && options.currentUser) || null;
|
||||||
|
|
||||||
|
applySchoolScope(where, currentUser?.app_role?.globalAccess, currentUser, 'schoolId');
|
||||||
|
|
||||||
const students = await db.students.findOne(
|
const students = await db.students.findOne(
|
||||||
{ where },
|
{ where },
|
||||||
@ -381,26 +389,11 @@ module.exports = class StudentsDBApi {
|
|||||||
let offset = 0;
|
let offset = 0;
|
||||||
let where = {};
|
let where = {};
|
||||||
const currentPage = +filter.page;
|
const currentPage = +filter.page;
|
||||||
|
|
||||||
|
|
||||||
const user = (options && options.currentUser) || null;
|
const user = (options && options.currentUser) || null;
|
||||||
const userSchools = (user && user.schools?.id) || null;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (userSchools) {
|
|
||||||
if (options?.currentUser?.schoolsId) {
|
|
||||||
where.schoolsId = options.currentUser.schoolsId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
offset = currentPage * limit;
|
offset = currentPage * limit;
|
||||||
|
|
||||||
const orderBy = null;
|
|
||||||
|
|
||||||
const transaction = (options && options.transaction) || undefined;
|
|
||||||
|
|
||||||
let include = [
|
let include = [
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -588,11 +581,7 @@ module.exports = class StudentsDBApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
applySchoolScope(where, globalAccess, user, 'schoolId');
|
||||||
if (globalAccess) {
|
|
||||||
delete where.schoolsId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const queryOptions = {
|
const queryOptions = {
|
||||||
where,
|
where,
|
||||||
@ -623,14 +612,9 @@ module.exports = class StudentsDBApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async findAllAutocomplete(query, limit, offset, globalAccess, organizationId,) {
|
static async findAllAutocomplete(query, limit, offset, globalAccess, schoolId,) {
|
||||||
let where = {};
|
let where = {};
|
||||||
|
|
||||||
|
|
||||||
if (!globalAccess && organizationId) {
|
|
||||||
where.organizationId = organizationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (query) {
|
if (query) {
|
||||||
where = {
|
where = {
|
||||||
@ -645,6 +629,8 @@ module.exports = class StudentsDBApi {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applySchoolScopeById(where, globalAccess, schoolId, 'schoolId');
|
||||||
|
|
||||||
const records = await db.students.findAll({
|
const records = await db.students.findAll({
|
||||||
attributes: [ 'id', 'nome_completo' ],
|
attributes: [ 'id', 'nome_completo' ],
|
||||||
where,
|
where,
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
|
|
||||||
const db = require('../models');
|
const db = require('../models');
|
||||||
const FileDBApi = require('./file');
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const Utils = require('../utils');
|
const Utils = require('../utils');
|
||||||
|
const { applySchoolScope, applySchoolScopeById, assertRecordInCurrentSchool, resolveSchoolIdForMutation } = require('./schoolScope');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -39,7 +38,7 @@ module.exports = class SubjectsDBApi {
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
await subjects.setSchool( data.school || null, {
|
await subjects.setSchool(resolveSchoolIdForMutation(data.school, currentUser), {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -73,6 +72,7 @@ module.exports = class SubjectsDBApi {
|
|||||||
importHash: item.importHash || null,
|
importHash: item.importHash || null,
|
||||||
createdById: currentUser.id,
|
createdById: currentUser.id,
|
||||||
updatedById: currentUser.id,
|
updatedById: currentUser.id,
|
||||||
|
schoolId: resolveSchoolIdForMutation(item.school, currentUser),
|
||||||
createdAt: new Date(Date.now() + index * 1000),
|
createdAt: new Date(Date.now() + index * 1000),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -88,9 +88,8 @@ module.exports = class SubjectsDBApi {
|
|||||||
static async update(id, data, options) {
|
static async update(id, data, options) {
|
||||||
const currentUser = (options && options.currentUser) || {id: null};
|
const currentUser = (options && options.currentUser) || {id: null};
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
const globalAccess = currentUser.app_role?.globalAccess;
|
|
||||||
|
|
||||||
const subjects = await db.subjects.findByPk(id, {}, {transaction});
|
const subjects = await db.subjects.findByPk(id, {}, {transaction});
|
||||||
|
assertRecordInCurrentSchool(subjects, currentUser, 'schoolId');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -112,7 +111,7 @@ module.exports = class SubjectsDBApi {
|
|||||||
if (data.school !== undefined) {
|
if (data.school !== undefined) {
|
||||||
await subjects.setSchool(
|
await subjects.setSchool(
|
||||||
|
|
||||||
data.school,
|
resolveSchoolIdForMutation(data.school, currentUser),
|
||||||
|
|
||||||
{ transaction }
|
{ transaction }
|
||||||
);
|
);
|
||||||
@ -140,6 +139,8 @@ module.exports = class SubjectsDBApi {
|
|||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
subjects.forEach((record) => assertRecordInCurrentSchool(record, currentUser, 'schoolId'));
|
||||||
|
|
||||||
await db.sequelize.transaction(async (transaction) => {
|
await db.sequelize.transaction(async (transaction) => {
|
||||||
for (const record of subjects) {
|
for (const record of subjects) {
|
||||||
await record.update(
|
await record.update(
|
||||||
@ -161,6 +162,7 @@ module.exports = class SubjectsDBApi {
|
|||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
|
||||||
const subjects = await db.subjects.findByPk(id, options);
|
const subjects = await db.subjects.findByPk(id, options);
|
||||||
|
assertRecordInCurrentSchool(subjects, currentUser, 'schoolId');
|
||||||
|
|
||||||
await subjects.update({
|
await subjects.update({
|
||||||
deletedBy: currentUser.id
|
deletedBy: currentUser.id
|
||||||
@ -177,6 +179,9 @@ module.exports = class SubjectsDBApi {
|
|||||||
|
|
||||||
static async findBy(where, options) {
|
static async findBy(where, options) {
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
const currentUser = (options && options.currentUser) || null;
|
||||||
|
|
||||||
|
applySchoolScope(where, currentUser?.app_role?.globalAccess, currentUser, 'schoolId');
|
||||||
|
|
||||||
const subjects = await db.subjects.findOne(
|
const subjects = await db.subjects.findOne(
|
||||||
{ where },
|
{ where },
|
||||||
@ -233,26 +238,11 @@ module.exports = class SubjectsDBApi {
|
|||||||
let offset = 0;
|
let offset = 0;
|
||||||
let where = {};
|
let where = {};
|
||||||
const currentPage = +filter.page;
|
const currentPage = +filter.page;
|
||||||
|
|
||||||
|
|
||||||
const user = (options && options.currentUser) || null;
|
const user = (options && options.currentUser) || null;
|
||||||
const userSchools = (user && user.schools?.id) || null;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (userSchools) {
|
|
||||||
if (options?.currentUser?.schoolsId) {
|
|
||||||
where.schoolsId = options.currentUser.schoolsId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
offset = currentPage * limit;
|
offset = currentPage * limit;
|
||||||
|
|
||||||
const orderBy = null;
|
|
||||||
|
|
||||||
const transaction = (options && options.transaction) || undefined;
|
|
||||||
|
|
||||||
let include = [
|
let include = [
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -349,11 +339,7 @@ module.exports = class SubjectsDBApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
applySchoolScope(where, globalAccess, user, 'schoolId');
|
||||||
if (globalAccess) {
|
|
||||||
delete where.schoolsId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const queryOptions = {
|
const queryOptions = {
|
||||||
where,
|
where,
|
||||||
@ -384,14 +370,9 @@ module.exports = class SubjectsDBApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async findAllAutocomplete(query, limit, offset, globalAccess, organizationId,) {
|
static async findAllAutocomplete(query, limit, offset, globalAccess, schoolId,) {
|
||||||
let where = {};
|
let where = {};
|
||||||
|
|
||||||
|
|
||||||
if (!globalAccess && organizationId) {
|
|
||||||
where.organizationId = organizationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (query) {
|
if (query) {
|
||||||
where = {
|
where = {
|
||||||
@ -406,6 +387,8 @@ module.exports = class SubjectsDBApi {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applySchoolScopeById(where, globalAccess, schoolId, 'schoolId');
|
||||||
|
|
||||||
const records = await db.subjects.findAll({
|
const records = await db.subjects.findAll({
|
||||||
attributes: [ 'id', 'nome' ],
|
attributes: [ 'id', 'nome' ],
|
||||||
where,
|
where,
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
|
|
||||||
const db = require('../models');
|
const db = require('../models');
|
||||||
const FileDBApi = require('./file');
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const Utils = require('../utils');
|
const Utils = require('../utils');
|
||||||
|
const { applySchoolScope, applySchoolScopeById, assertRecordInCurrentSchool, resolveSchoolIdForMutation } = require('./schoolScope');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -54,7 +53,7 @@ module.exports = class TeachersDBApi {
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
await teachers.setSchool( data.school || null, {
|
await teachers.setSchool(resolveSchoolIdForMutation(data.school, currentUser), {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -103,6 +102,7 @@ module.exports = class TeachersDBApi {
|
|||||||
importHash: item.importHash || null,
|
importHash: item.importHash || null,
|
||||||
createdById: currentUser.id,
|
createdById: currentUser.id,
|
||||||
updatedById: currentUser.id,
|
updatedById: currentUser.id,
|
||||||
|
schoolId: resolveSchoolIdForMutation(item.school, currentUser),
|
||||||
createdAt: new Date(Date.now() + index * 1000),
|
createdAt: new Date(Date.now() + index * 1000),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -118,9 +118,8 @@ module.exports = class TeachersDBApi {
|
|||||||
static async update(id, data, options) {
|
static async update(id, data, options) {
|
||||||
const currentUser = (options && options.currentUser) || {id: null};
|
const currentUser = (options && options.currentUser) || {id: null};
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
const globalAccess = currentUser.app_role?.globalAccess;
|
|
||||||
|
|
||||||
const teachers = await db.teachers.findByPk(id, {}, {transaction});
|
const teachers = await db.teachers.findByPk(id, {}, {transaction});
|
||||||
|
assertRecordInCurrentSchool(teachers, currentUser, 'schoolId');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -151,7 +150,7 @@ module.exports = class TeachersDBApi {
|
|||||||
if (data.school !== undefined) {
|
if (data.school !== undefined) {
|
||||||
await teachers.setSchool(
|
await teachers.setSchool(
|
||||||
|
|
||||||
data.school,
|
resolveSchoolIdForMutation(data.school, currentUser),
|
||||||
|
|
||||||
{ transaction }
|
{ transaction }
|
||||||
);
|
);
|
||||||
@ -179,6 +178,8 @@ module.exports = class TeachersDBApi {
|
|||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
teachers.forEach((record) => assertRecordInCurrentSchool(record, currentUser, 'schoolId'));
|
||||||
|
|
||||||
await db.sequelize.transaction(async (transaction) => {
|
await db.sequelize.transaction(async (transaction) => {
|
||||||
for (const record of teachers) {
|
for (const record of teachers) {
|
||||||
await record.update(
|
await record.update(
|
||||||
@ -200,6 +201,7 @@ module.exports = class TeachersDBApi {
|
|||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
|
||||||
const teachers = await db.teachers.findByPk(id, options);
|
const teachers = await db.teachers.findByPk(id, options);
|
||||||
|
assertRecordInCurrentSchool(teachers, currentUser, 'schoolId');
|
||||||
|
|
||||||
await teachers.update({
|
await teachers.update({
|
||||||
deletedBy: currentUser.id
|
deletedBy: currentUser.id
|
||||||
@ -216,6 +218,9 @@ module.exports = class TeachersDBApi {
|
|||||||
|
|
||||||
static async findBy(where, options) {
|
static async findBy(where, options) {
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
const currentUser = (options && options.currentUser) || null;
|
||||||
|
|
||||||
|
applySchoolScope(where, currentUser?.app_role?.globalAccess, currentUser, 'schoolId');
|
||||||
|
|
||||||
const teachers = await db.teachers.findOne(
|
const teachers = await db.teachers.findOne(
|
||||||
{ where },
|
{ where },
|
||||||
@ -272,26 +277,11 @@ module.exports = class TeachersDBApi {
|
|||||||
let offset = 0;
|
let offset = 0;
|
||||||
let where = {};
|
let where = {};
|
||||||
const currentPage = +filter.page;
|
const currentPage = +filter.page;
|
||||||
|
|
||||||
|
|
||||||
const user = (options && options.currentUser) || null;
|
const user = (options && options.currentUser) || null;
|
||||||
const userSchools = (user && user.schools?.id) || null;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (userSchools) {
|
|
||||||
if (options?.currentUser?.schoolsId) {
|
|
||||||
where.schoolsId = options.currentUser.schoolsId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
offset = currentPage * limit;
|
offset = currentPage * limit;
|
||||||
|
|
||||||
const orderBy = null;
|
|
||||||
|
|
||||||
const transaction = (options && options.transaction) || undefined;
|
|
||||||
|
|
||||||
let include = [
|
let include = [
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -421,11 +411,7 @@ module.exports = class TeachersDBApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
applySchoolScope(where, globalAccess, user, 'schoolId');
|
||||||
if (globalAccess) {
|
|
||||||
delete where.schoolsId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const queryOptions = {
|
const queryOptions = {
|
||||||
where,
|
where,
|
||||||
@ -456,14 +442,9 @@ module.exports = class TeachersDBApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async findAllAutocomplete(query, limit, offset, globalAccess, organizationId,) {
|
static async findAllAutocomplete(query, limit, offset, globalAccess, schoolId,) {
|
||||||
let where = {};
|
let where = {};
|
||||||
|
|
||||||
|
|
||||||
if (!globalAccess && organizationId) {
|
|
||||||
where.organizationId = organizationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (query) {
|
if (query) {
|
||||||
where = {
|
where = {
|
||||||
@ -478,6 +459,8 @@ module.exports = class TeachersDBApi {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applySchoolScopeById(where, globalAccess, schoolId, 'schoolId');
|
||||||
|
|
||||||
const records = await db.teachers.findAll({
|
const records = await db.teachers.findAll({
|
||||||
attributes: [ 'id', 'nome' ],
|
attributes: [ 'id', 'nome' ],
|
||||||
where,
|
where,
|
||||||
|
|||||||
@ -3,6 +3,8 @@ const db = require('../models');
|
|||||||
const FileDBApi = require('./file');
|
const FileDBApi = require('./file');
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
const Utils = require('../utils');
|
const Utils = require('../utils');
|
||||||
|
const ForbiddenError = require('../../services/notifications/errors/forbidden');
|
||||||
|
const { applySchoolScope, applySchoolScopeById, assertRecordInCurrentSchool, resolveSchoolIdForMutation } = require('./schoolScope');
|
||||||
|
|
||||||
const bcrypt = require('bcrypt');
|
const bcrypt = require('bcrypt');
|
||||||
const config = require('../../config');
|
const config = require('../../config');
|
||||||
@ -12,12 +14,71 @@ const config = require('../../config');
|
|||||||
const Sequelize = db.Sequelize;
|
const Sequelize = db.Sequelize;
|
||||||
const Op = Sequelize.Op;
|
const Op = Sequelize.Op;
|
||||||
|
|
||||||
|
|
||||||
|
async function assertAssignableRole(roleId, currentUser, transaction) {
|
||||||
|
if (!roleId || currentUser?.app_role?.globalAccess) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const role = await db.roles.findByPk(roleId, { transaction });
|
||||||
|
if (!role || role.globalAccess) {
|
||||||
|
throw new ForbiddenError('auth.forbidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function assertSafeSelfUpdate(id, data, currentUser) {
|
||||||
|
if (
|
||||||
|
!currentUser?.id ||
|
||||||
|
String(currentUser.id) !== String(id) ||
|
||||||
|
currentUser?.app_role?.globalAccess
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const restrictedFields = [
|
||||||
|
'app_role',
|
||||||
|
'custom_permissions',
|
||||||
|
'schools',
|
||||||
|
'disabled',
|
||||||
|
'email',
|
||||||
|
'emailVerified',
|
||||||
|
'emailVerificationToken',
|
||||||
|
'emailVerificationTokenExpiresAt',
|
||||||
|
'passwordResetToken',
|
||||||
|
'passwordResetTokenExpiresAt',
|
||||||
|
'provider',
|
||||||
|
];
|
||||||
|
|
||||||
|
const hasRestrictedField = restrictedFields.some((field) => (
|
||||||
|
Object.prototype.hasOwnProperty.call(data || {}, field) && data[field] !== undefined
|
||||||
|
));
|
||||||
|
|
||||||
|
if (hasRestrictedField) {
|
||||||
|
throw new ForbiddenError('auth.forbidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertCanAssignCustomPermissions(customPermissions, currentUser) {
|
||||||
|
if (currentUser?.app_role?.globalAccess || customPermissions === undefined || customPermissions === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(customPermissions) && customPermissions.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ForbiddenError('auth.forbidden');
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = class UsersDBApi {
|
module.exports = class UsersDBApi {
|
||||||
|
|
||||||
static async create(data,globalAccess, options) {
|
static async create(data,globalAccess, options) {
|
||||||
const currentUser = (options && options.currentUser) || { id: null };
|
const currentUser = (options && options.currentUser) || { id: null };
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
|
||||||
|
await assertAssignableRole(data.data.app_role, currentUser, transaction);
|
||||||
|
assertCanAssignCustomPermissions(data.data.custom_permissions, currentUser);
|
||||||
|
|
||||||
const users = await db.users.create(
|
const users = await db.users.create(
|
||||||
{
|
{
|
||||||
@ -112,7 +173,7 @@ module.exports = class UsersDBApi {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
await users.setSchools( data.data.schools || null, {
|
await users.setSchools(resolveSchoolIdForMutation(data.data.schools, currentUser), {
|
||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -215,6 +276,7 @@ module.exports = class UsersDBApi {
|
|||||||
importHash: item.importHash || null,
|
importHash: item.importHash || null,
|
||||||
createdById: currentUser.id,
|
createdById: currentUser.id,
|
||||||
updatedById: currentUser.id,
|
updatedById: currentUser.id,
|
||||||
|
schoolsId: resolveSchoolIdForMutation(item.schools, currentUser),
|
||||||
createdAt: new Date(Date.now() + index * 1000),
|
createdAt: new Date(Date.now() + index * 1000),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -242,10 +304,20 @@ module.exports = class UsersDBApi {
|
|||||||
static async update(id, data, globalAccess, options) {
|
static async update(id, data, globalAccess, options) {
|
||||||
const currentUser = (options && options.currentUser) || {id: null};
|
const currentUser = (options && options.currentUser) || {id: null};
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
assertSafeSelfUpdate(id, data, currentUser);
|
||||||
|
const appRoleProvided = Object.prototype.hasOwnProperty.call(data || {}, 'app_role');
|
||||||
|
const customPermissionsProvided = Object.prototype.hasOwnProperty.call(data || {}, 'custom_permissions');
|
||||||
|
|
||||||
|
|
||||||
const users = await db.users.findByPk(id, {}, {transaction});
|
const users = await db.users.findByPk(id, {}, {transaction});
|
||||||
|
assertRecordInCurrentSchool(users, currentUser, 'schoolsId');
|
||||||
|
|
||||||
|
if (appRoleProvided) {
|
||||||
|
await assertAssignableRole(data.app_role, currentUser, transaction);
|
||||||
|
}
|
||||||
|
if (customPermissionsProvided) {
|
||||||
|
assertCanAssignCustomPermissions(data.custom_permissions, currentUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -324,7 +396,7 @@ module.exports = class UsersDBApi {
|
|||||||
if (data.schools !== undefined) {
|
if (data.schools !== undefined) {
|
||||||
await users.setSchools(
|
await users.setSchools(
|
||||||
|
|
||||||
data.schools,
|
resolveSchoolIdForMutation(data.schools, currentUser),
|
||||||
|
|
||||||
{ transaction }
|
{ transaction }
|
||||||
);
|
);
|
||||||
@ -339,15 +411,17 @@ module.exports = class UsersDBApi {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
await FileDBApi.replaceRelationFiles(
|
if (data.avatar !== undefined) {
|
||||||
{
|
await FileDBApi.replaceRelationFiles(
|
||||||
belongsTo: db.users.getTableName(),
|
{
|
||||||
belongsToColumn: 'avatar',
|
belongsTo: db.users.getTableName(),
|
||||||
belongsToId: users.id,
|
belongsToColumn: 'avatar',
|
||||||
},
|
belongsToId: users.id,
|
||||||
data.avatar,
|
},
|
||||||
options,
|
data.avatar,
|
||||||
);
|
options,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return users;
|
return users;
|
||||||
@ -366,6 +440,8 @@ module.exports = class UsersDBApi {
|
|||||||
transaction,
|
transaction,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
users.forEach((record) => assertRecordInCurrentSchool(record, currentUser, 'schoolsId'));
|
||||||
|
|
||||||
await db.sequelize.transaction(async (transaction) => {
|
await db.sequelize.transaction(async (transaction) => {
|
||||||
for (const record of users) {
|
for (const record of users) {
|
||||||
await record.update(
|
await record.update(
|
||||||
@ -387,6 +463,7 @@ module.exports = class UsersDBApi {
|
|||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
|
||||||
const users = await db.users.findByPk(id, options);
|
const users = await db.users.findByPk(id, options);
|
||||||
|
assertRecordInCurrentSchool(users, currentUser, 'schoolsId');
|
||||||
|
|
||||||
await users.update({
|
await users.update({
|
||||||
deletedBy: currentUser.id
|
deletedBy: currentUser.id
|
||||||
@ -403,6 +480,9 @@ module.exports = class UsersDBApi {
|
|||||||
|
|
||||||
static async findBy(where, options) {
|
static async findBy(where, options) {
|
||||||
const transaction = (options && options.transaction) || undefined;
|
const transaction = (options && options.transaction) || undefined;
|
||||||
|
const currentUser = (options && options.currentUser) || null;
|
||||||
|
|
||||||
|
applySchoolScope(where, currentUser?.app_role?.globalAccess, currentUser, 'schoolsId');
|
||||||
|
|
||||||
const users = await db.users.findOne(
|
const users = await db.users.findOne(
|
||||||
{ where },
|
{ where },
|
||||||
@ -476,26 +556,11 @@ module.exports = class UsersDBApi {
|
|||||||
let offset = 0;
|
let offset = 0;
|
||||||
let where = {};
|
let where = {};
|
||||||
const currentPage = +filter.page;
|
const currentPage = +filter.page;
|
||||||
|
|
||||||
|
|
||||||
const user = (options && options.currentUser) || null;
|
const user = (options && options.currentUser) || null;
|
||||||
const userSchools = (user && user.schools?.id) || null;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (userSchools) {
|
|
||||||
if (options?.currentUser?.schoolsId) {
|
|
||||||
where.schoolsId = options.currentUser.schoolsId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
offset = currentPage * limit;
|
offset = currentPage * limit;
|
||||||
|
|
||||||
const orderBy = null;
|
|
||||||
|
|
||||||
const transaction = (options && options.transaction) || undefined;
|
|
||||||
|
|
||||||
let include = [
|
let include = [
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -777,11 +842,7 @@ module.exports = class UsersDBApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
applySchoolScope(where, globalAccess, user, 'schoolsId');
|
||||||
if (globalAccess) {
|
|
||||||
delete where.schoolsId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const queryOptions = {
|
const queryOptions = {
|
||||||
where,
|
where,
|
||||||
@ -812,14 +873,9 @@ module.exports = class UsersDBApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async findAllAutocomplete(query, limit, offset, globalAccess, organizationId,) {
|
static async findAllAutocomplete(query, limit, offset, globalAccess, schoolId,) {
|
||||||
let where = {};
|
let where = {};
|
||||||
|
|
||||||
|
|
||||||
if (!globalAccess && organizationId) {
|
|
||||||
where.organizationId = organizationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (query) {
|
if (query) {
|
||||||
where = {
|
where = {
|
||||||
@ -834,6 +890,8 @@ module.exports = class UsersDBApi {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applySchoolScopeById(where, globalAccess, schoolId, 'schoolsId');
|
||||||
|
|
||||||
const records = await db.users.findAll({
|
const records = await db.users.findAll({
|
||||||
attributes: [ 'id', 'firstName' ],
|
attributes: [ 'id', 'firstName' ],
|
||||||
where,
|
where,
|
||||||
@ -858,7 +916,7 @@ module.exports = class UsersDBApi {
|
|||||||
authenticationUid: data.authenticationUid,
|
authenticationUid: data.authenticationUid,
|
||||||
password: data.password,
|
password: data.password,
|
||||||
|
|
||||||
organizationId: data.organizationId,
|
schoolsId: data.organizationId,
|
||||||
|
|
||||||
},
|
},
|
||||||
{ transaction },
|
{ transaction },
|
||||||
|
|||||||
@ -2777,7 +2777,7 @@ module.exports = {
|
|||||||
* @param {Sequelize} Sequelize
|
* @param {Sequelize} Sequelize
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
async down(queryInterface, Sequelize) {
|
async down(queryInterface) {
|
||||||
/**
|
/**
|
||||||
* @type {Transaction}
|
* @type {Transaction}
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -0,0 +1,50 @@
|
|||||||
|
module.exports = {
|
||||||
|
async up(queryInterface, Sequelize) {
|
||||||
|
const transaction = await queryInterface.sequelize.transaction();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await queryInterface.addColumn('schools', 'nif', { type: Sequelize.DataTypes.TEXT }, { transaction });
|
||||||
|
await queryInterface.addColumn('schools', 'phone', { type: Sequelize.DataTypes.TEXT }, { transaction });
|
||||||
|
await queryInterface.addColumn('schools', 'email', { type: Sequelize.DataTypes.TEXT }, { transaction });
|
||||||
|
await queryInterface.addColumn('schools', 'province', { type: Sequelize.DataTypes.TEXT }, { transaction });
|
||||||
|
await queryInterface.addColumn('schools', 'municipality', { type: Sequelize.DataTypes.TEXT }, { transaction });
|
||||||
|
await queryInterface.addColumn('schools', 'address', { type: Sequelize.DataTypes.TEXT }, { transaction });
|
||||||
|
await queryInterface.addColumn('schools', 'logoUrl', { type: Sequelize.DataTypes.TEXT }, { transaction });
|
||||||
|
await queryInterface.addColumn(
|
||||||
|
'schools',
|
||||||
|
'status',
|
||||||
|
{
|
||||||
|
type: Sequelize.DataTypes.TEXT,
|
||||||
|
allowNull: false,
|
||||||
|
defaultValue: 'active',
|
||||||
|
},
|
||||||
|
{ transaction },
|
||||||
|
);
|
||||||
|
|
||||||
|
await transaction.commit();
|
||||||
|
} catch (error) {
|
||||||
|
await transaction.rollback();
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async down(queryInterface) {
|
||||||
|
const transaction = await queryInterface.sequelize.transaction();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await queryInterface.removeColumn('schools', 'status', { transaction });
|
||||||
|
await queryInterface.removeColumn('schools', 'logoUrl', { transaction });
|
||||||
|
await queryInterface.removeColumn('schools', 'address', { transaction });
|
||||||
|
await queryInterface.removeColumn('schools', 'municipality', { transaction });
|
||||||
|
await queryInterface.removeColumn('schools', 'province', { transaction });
|
||||||
|
await queryInterface.removeColumn('schools', 'email', { transaction });
|
||||||
|
await queryInterface.removeColumn('schools', 'phone', { transaction });
|
||||||
|
await queryInterface.removeColumn('schools', 'nif', { transaction });
|
||||||
|
|
||||||
|
await transaction.commit();
|
||||||
|
} catch (error) {
|
||||||
|
await transaction.rollback();
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
@ -1,8 +1,3 @@
|
|||||||
const config = require('../../config');
|
|
||||||
const providers = config.providers;
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const bcrypt = require('bcrypt');
|
|
||||||
const moment = require('moment');
|
|
||||||
|
|
||||||
module.exports = function(sequelize, DataTypes) {
|
module.exports = function(sequelize, DataTypes) {
|
||||||
const assessments = sequelize.define(
|
const assessments = sequelize.define(
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
const config = require('../../config');
|
|
||||||
const providers = config.providers;
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const bcrypt = require('bcrypt');
|
|
||||||
const moment = require('moment');
|
|
||||||
|
|
||||||
module.exports = function(sequelize, DataTypes) {
|
module.exports = function(sequelize, DataTypes) {
|
||||||
const attendance = sequelize.define(
|
const attendance = sequelize.define(
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
const config = require('../../config');
|
|
||||||
const providers = config.providers;
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const bcrypt = require('bcrypt');
|
|
||||||
const moment = require('moment');
|
|
||||||
|
|
||||||
module.exports = function(sequelize, DataTypes) {
|
module.exports = function(sequelize, DataTypes) {
|
||||||
const book_loans = sequelize.define(
|
const book_loans = sequelize.define(
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
const config = require('../../config');
|
|
||||||
const providers = config.providers;
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const bcrypt = require('bcrypt');
|
|
||||||
const moment = require('moment');
|
|
||||||
|
|
||||||
module.exports = function(sequelize, DataTypes) {
|
module.exports = function(sequelize, DataTypes) {
|
||||||
const books = sequelize.define(
|
const books = sequelize.define(
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
const config = require('../../config');
|
|
||||||
const providers = config.providers;
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const bcrypt = require('bcrypt');
|
|
||||||
const moment = require('moment');
|
|
||||||
|
|
||||||
module.exports = function(sequelize, DataTypes) {
|
module.exports = function(sequelize, DataTypes) {
|
||||||
const classes = sequelize.define(
|
const classes = sequelize.define(
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
const config = require('../../config');
|
|
||||||
const providers = config.providers;
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const bcrypt = require('bcrypt');
|
|
||||||
const moment = require('moment');
|
|
||||||
|
|
||||||
module.exports = function(sequelize, DataTypes) {
|
module.exports = function(sequelize, DataTypes) {
|
||||||
const courses = sequelize.define(
|
const courses = sequelize.define(
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
const config = require('../../config');
|
|
||||||
const providers = config.providers;
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const bcrypt = require('bcrypt');
|
|
||||||
const moment = require('moment');
|
|
||||||
|
|
||||||
module.exports = function(sequelize, DataTypes) {
|
module.exports = function(sequelize, DataTypes) {
|
||||||
const employees = sequelize.define(
|
const employees = sequelize.define(
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
const config = require('../../config');
|
|
||||||
const providers = config.providers;
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const bcrypt = require('bcrypt');
|
|
||||||
const moment = require('moment');
|
|
||||||
|
|
||||||
module.exports = function(sequelize, DataTypes) {
|
module.exports = function(sequelize, DataTypes) {
|
||||||
const enrollments = sequelize.define(
|
const enrollments = sequelize.define(
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
const config = require('../../config');
|
|
||||||
const providers = config.providers;
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const bcrypt = require('bcrypt');
|
|
||||||
const moment = require('moment');
|
|
||||||
|
|
||||||
module.exports = function(sequelize, DataTypes) {
|
module.exports = function(sequelize, DataTypes) {
|
||||||
const grades = sequelize.define(
|
const grades = sequelize.define(
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
const config = require('../../config');
|
|
||||||
const providers = config.providers;
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const bcrypt = require('bcrypt');
|
|
||||||
const moment = require('moment');
|
|
||||||
|
|
||||||
module.exports = function(sequelize, DataTypes) {
|
module.exports = function(sequelize, DataTypes) {
|
||||||
const guardians = sequelize.define(
|
const guardians = sequelize.define(
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
const config = require('../../config');
|
|
||||||
const providers = config.providers;
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const bcrypt = require('bcrypt');
|
|
||||||
const moment = require('moment');
|
|
||||||
|
|
||||||
module.exports = function(sequelize, DataTypes) {
|
module.exports = function(sequelize, DataTypes) {
|
||||||
const invoices = sequelize.define(
|
const invoices = sequelize.define(
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
const config = require('../../config');
|
|
||||||
const providers = config.providers;
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const bcrypt = require('bcrypt');
|
|
||||||
const moment = require('moment');
|
|
||||||
|
|
||||||
module.exports = function(sequelize, DataTypes) {
|
module.exports = function(sequelize, DataTypes) {
|
||||||
const payments = sequelize.define(
|
const payments = sequelize.define(
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
const config = require('../../config');
|
|
||||||
const providers = config.providers;
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const bcrypt = require('bcrypt');
|
|
||||||
const moment = require('moment');
|
|
||||||
|
|
||||||
module.exports = function(sequelize, DataTypes) {
|
module.exports = function(sequelize, DataTypes) {
|
||||||
const permissions = sequelize.define(
|
const permissions = sequelize.define(
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
const config = require('../../config');
|
|
||||||
const providers = config.providers;
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const bcrypt = require('bcrypt');
|
|
||||||
const moment = require('moment');
|
|
||||||
|
|
||||||
module.exports = function(sequelize, DataTypes) {
|
module.exports = function(sequelize, DataTypes) {
|
||||||
const products = sequelize.define(
|
const products = sequelize.define(
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
const config = require('../../config');
|
|
||||||
const providers = config.providers;
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const bcrypt = require('bcrypt');
|
|
||||||
const moment = require('moment');
|
|
||||||
|
|
||||||
module.exports = function(sequelize, DataTypes) {
|
module.exports = function(sequelize, DataTypes) {
|
||||||
const roles = sequelize.define(
|
const roles = sequelize.define(
|
||||||
|
|||||||
@ -1,9 +1,3 @@
|
|||||||
const config = require('../../config');
|
|
||||||
const providers = config.providers;
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const bcrypt = require('bcrypt');
|
|
||||||
const moment = require('moment');
|
|
||||||
|
|
||||||
module.exports = function(sequelize, DataTypes) {
|
module.exports = function(sequelize, DataTypes) {
|
||||||
const schools = sequelize.define(
|
const schools = sequelize.define(
|
||||||
'schools',
|
'schools',
|
||||||
@ -19,6 +13,63 @@ name: {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
nif: {
|
||||||
|
type: DataTypes.TEXT,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
phone: {
|
||||||
|
type: DataTypes.TEXT,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
email: {
|
||||||
|
type: DataTypes.TEXT,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
province: {
|
||||||
|
type: DataTypes.TEXT,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
municipality: {
|
||||||
|
type: DataTypes.TEXT,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
address: {
|
||||||
|
type: DataTypes.TEXT,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
logoUrl: {
|
||||||
|
type: DataTypes.TEXT,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
status: {
|
||||||
|
type: DataTypes.TEXT,
|
||||||
|
allowNull: false,
|
||||||
|
defaultValue: 'active',
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
importHash: {
|
importHash: {
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
const config = require('../../config');
|
|
||||||
const providers = config.providers;
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const bcrypt = require('bcrypt');
|
|
||||||
const moment = require('moment');
|
|
||||||
|
|
||||||
module.exports = function(sequelize, DataTypes) {
|
module.exports = function(sequelize, DataTypes) {
|
||||||
const student_guardians = sequelize.define(
|
const student_guardians = sequelize.define(
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
const config = require('../../config');
|
|
||||||
const providers = config.providers;
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const bcrypt = require('bcrypt');
|
|
||||||
const moment = require('moment');
|
|
||||||
|
|
||||||
module.exports = function(sequelize, DataTypes) {
|
module.exports = function(sequelize, DataTypes) {
|
||||||
const students = sequelize.define(
|
const students = sequelize.define(
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
const config = require('../../config');
|
|
||||||
const providers = config.providers;
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const bcrypt = require('bcrypt');
|
|
||||||
const moment = require('moment');
|
|
||||||
|
|
||||||
module.exports = function(sequelize, DataTypes) {
|
module.exports = function(sequelize, DataTypes) {
|
||||||
const subjects = sequelize.define(
|
const subjects = sequelize.define(
|
||||||
|
|||||||
@ -1,8 +1,3 @@
|
|||||||
const config = require('../../config');
|
|
||||||
const providers = config.providers;
|
|
||||||
const crypto = require('crypto');
|
|
||||||
const bcrypt = require('bcrypt');
|
|
||||||
const moment = require('moment');
|
|
||||||
|
|
||||||
module.exports = function(sequelize, DataTypes) {
|
module.exports = function(sequelize, DataTypes) {
|
||||||
const teachers = sequelize.define(
|
const teachers = sequelize.define(
|
||||||
|
|||||||
@ -2,7 +2,6 @@ const config = require('../../config');
|
|||||||
const providers = config.providers;
|
const providers = config.providers;
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
const bcrypt = require('bcrypt');
|
const bcrypt = require('bcrypt');
|
||||||
const moment = require('moment');
|
|
||||||
|
|
||||||
module.exports = function(sequelize, DataTypes) {
|
module.exports = function(sequelize, DataTypes) {
|
||||||
const users = sequelize.define(
|
const users = sequelize.define(
|
||||||
@ -206,13 +205,13 @@ provider: {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
users.beforeCreate((users, options) => {
|
users.beforeCreate((user) => {
|
||||||
users = trimStringFields(users);
|
trimStringFields(user);
|
||||||
|
|
||||||
if (users.provider !== providers.LOCAL && Object.values(providers).indexOf(users.provider) > -1) {
|
if (user.provider !== providers.LOCAL && Object.values(providers).indexOf(user.provider) > -1) {
|
||||||
users.emailVerified = true;
|
user.emailVerified = true;
|
||||||
|
|
||||||
if (!users.password) {
|
if (!user.password) {
|
||||||
const password = crypto
|
const password = crypto
|
||||||
.randomBytes(20)
|
.randomBytes(20)
|
||||||
.toString('hex');
|
.toString('hex');
|
||||||
@ -222,13 +221,13 @@ provider: {
|
|||||||
config.bcrypt.saltRounds,
|
config.bcrypt.saltRounds,
|
||||||
);
|
);
|
||||||
|
|
||||||
users.password = hashedPassword
|
user.password = hashedPassword
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
users.beforeUpdate((users, options) => {
|
users.beforeUpdate((user) => {
|
||||||
users = trimStringFields(users);
|
trimStringFields(user);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ const ids = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
up: async (queryInterface, Sequelize) => {
|
up: async (queryInterface) => {
|
||||||
let admin_hash = bcrypt.hashSync(config.admin_pass, config.bcrypt.saltRounds);
|
let admin_hash = bcrypt.hashSync(config.admin_pass, config.bcrypt.saltRounds);
|
||||||
let user_hash = bcrypt.hashSync(config.user_pass, config.bcrypt.saltRounds);
|
let user_hash = bcrypt.hashSync(config.user_pass, config.bcrypt.saltRounds);
|
||||||
|
|
||||||
|
|||||||
@ -63,7 +63,7 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const entities = [
|
const entities = [
|
||||||
"users","roles","permissions","schools","students","guardians","student_guardians","teachers","courses","grades","classes","subjects","enrollments","assessments","attendance","invoices","payments","employees","products","books","book_loans",,
|
"users","roles","permissions","schools","students","guardians","student_guardians","teachers","courses","grades","classes","subjects","enrollments","assessments","attendance","invoices","payments","employees","products","books","book_loans",
|
||||||
];
|
];
|
||||||
await queryInterface.bulkInsert("permissions", entities.flatMap(createPermissions));
|
await queryInterface.bulkInsert("permissions", entities.flatMap(createPermissions));
|
||||||
await queryInterface.bulkInsert("permissions", [{ id: getId(`READ_API_DOCS`), createdAt, updatedAt, name: `READ_API_DOCS` }]);
|
await queryInterface.bulkInsert("permissions", [{ id: getId(`READ_API_DOCS`), createdAt, updatedAt, name: `READ_API_DOCS` }]);
|
||||||
|
|||||||
@ -4450,7 +4450,7 @@ const BookLoansData = [
|
|||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
up: async (queryInterface, Sequelize) => {
|
up: async () => {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -4954,7 +4954,7 @@ module.exports = {
|
|||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
down: async (queryInterface, Sequelize) => {
|
down: async (queryInterface) => {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,7 @@ module.exports = class Helpers {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static commonErrorHandler(error, req, res, next) {
|
static commonErrorHandler(error, req, res) {
|
||||||
if ([400, 403, 404].includes(error.code)) {
|
if ([400, 403, 404].includes(error.code)) {
|
||||||
return res.status(error.code).send(error.message);
|
return res.status(error.code).send(error.message);
|
||||||
}
|
}
|
||||||
@ -19,5 +19,5 @@ module.exports = class Helpers {
|
|||||||
|
|
||||||
static jwtSign(data) {
|
static jwtSign(data) {
|
||||||
return jwt.sign(data, config.secret_key, {expiresIn: '6h'});
|
return jwt.sign(data, config.secret_key, {expiresIn: '6h'});
|
||||||
};
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -6,7 +6,6 @@ const passport = require('passport');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const bodyParser = require('body-parser');
|
const bodyParser = require('body-parser');
|
||||||
const db = require('./db/models');
|
|
||||||
const config = require('./config');
|
const config = require('./config');
|
||||||
const swaggerUI = require('swagger-ui-express');
|
const swaggerUI = require('swagger-ui-express');
|
||||||
const swaggerJsDoc = require('swagger-jsdoc');
|
const swaggerJsDoc = require('swagger-jsdoc');
|
||||||
|
|||||||
@ -42,9 +42,12 @@ function checkPermissions(permission) {
|
|||||||
return async (req, res, next) => {
|
return async (req, res, next) => {
|
||||||
const { currentUser } = req;
|
const { currentUser } = req;
|
||||||
|
|
||||||
// 1. Check self-access bypass (only if the user is authenticated)
|
// 1. Check self-access bypass for reading the authenticated user's own record only.
|
||||||
if (currentUser && (currentUser.id === req.params.id || currentUser.id === req.body.id)) {
|
const isSelfAccess = currentUser && (
|
||||||
return next(); // User has access to their own resource
|
currentUser.id === req.params.id || currentUser.id === req.body?.id
|
||||||
|
);
|
||||||
|
if (isSelfAccess && permission === 'READ_USERS') {
|
||||||
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Check Custom Permissions (only if the user is authenticated)
|
// 2. Check Custom Permissions (only if the user is authenticated)
|
||||||
@ -135,9 +138,10 @@ const METHOD_MAP = {
|
|||||||
*/
|
*/
|
||||||
function checkCrudPermissions(name) {
|
function checkCrudPermissions(name) {
|
||||||
return (req, res, next) => {
|
return (req, res, next) => {
|
||||||
// Dynamically determine the permission name (e.g., 'READ_USERS')
|
const methodAction = req.path.replace(/\/$/, '') === '/deleteByIds'
|
||||||
const permissionName = `${METHOD_MAP[req.method]}_${name.toUpperCase()}`;
|
? 'DELETE'
|
||||||
// Call the checkPermissions middleware with the determined permission
|
: METHOD_MAP[req.method];
|
||||||
|
const permissionName = `${methodAction}_${name.toUpperCase()}`;
|
||||||
checkPermissions(permissionName)(req, res, next);
|
checkPermissions(permissionName)(req, res, next);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,10 +3,9 @@ const express = require('express');
|
|||||||
|
|
||||||
const AssessmentsService = require('../services/assessments');
|
const AssessmentsService = require('../services/assessments');
|
||||||
const AssessmentsDBApi = require('../db/api/assessments');
|
const AssessmentsDBApi = require('../db/api/assessments');
|
||||||
|
const { getCurrentUserSchoolId } = require('../db/api/schoolScope');
|
||||||
const wrapAsync = require('../helpers').wrapAsync;
|
const wrapAsync = require('../helpers').wrapAsync;
|
||||||
|
|
||||||
const config = require('../config');
|
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@ -309,6 +308,7 @@ router.get('/', wrapAsync(async (req, res) => {
|
|||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -384,14 +384,14 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
|
|
||||||
const globalAccess = req.currentUser.app_role.globalAccess;
|
const globalAccess = req.currentUser.app_role.globalAccess;
|
||||||
|
|
||||||
const organizationId = req.currentUser.organization?.id
|
const schoolId = getCurrentUserSchoolId(req.currentUser);
|
||||||
|
|
||||||
|
|
||||||
const payload = await AssessmentsDBApi.findAllAutocomplete(
|
const payload = await AssessmentsDBApi.findAllAutocomplete(
|
||||||
req.query.query,
|
req.query.query,
|
||||||
req.query.limit,
|
req.query.limit,
|
||||||
req.query.offset,
|
req.query.offset,
|
||||||
globalAccess, organizationId,
|
globalAccess, schoolId,
|
||||||
);
|
);
|
||||||
|
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -432,6 +432,7 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
router.get('/:id', wrapAsync(async (req, res) => {
|
router.get('/:id', wrapAsync(async (req, res) => {
|
||||||
const payload = await AssessmentsDBApi.findBy(
|
const payload = await AssessmentsDBApi.findBy(
|
||||||
{ id: req.params.id },
|
{ id: req.params.id },
|
||||||
|
{ currentUser: req.currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -3,10 +3,9 @@ const express = require('express');
|
|||||||
|
|
||||||
const AttendanceService = require('../services/attendance');
|
const AttendanceService = require('../services/attendance');
|
||||||
const AttendanceDBApi = require('../db/api/attendance');
|
const AttendanceDBApi = require('../db/api/attendance');
|
||||||
|
const { getCurrentUserSchoolId } = require('../db/api/schoolScope');
|
||||||
const wrapAsync = require('../helpers').wrapAsync;
|
const wrapAsync = require('../helpers').wrapAsync;
|
||||||
|
|
||||||
const config = require('../config');
|
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@ -305,6 +304,7 @@ router.get('/', wrapAsync(async (req, res) => {
|
|||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -380,14 +380,14 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
|
|
||||||
const globalAccess = req.currentUser.app_role.globalAccess;
|
const globalAccess = req.currentUser.app_role.globalAccess;
|
||||||
|
|
||||||
const organizationId = req.currentUser.organization?.id
|
const schoolId = getCurrentUserSchoolId(req.currentUser);
|
||||||
|
|
||||||
|
|
||||||
const payload = await AttendanceDBApi.findAllAutocomplete(
|
const payload = await AttendanceDBApi.findAllAutocomplete(
|
||||||
req.query.query,
|
req.query.query,
|
||||||
req.query.limit,
|
req.query.limit,
|
||||||
req.query.offset,
|
req.query.offset,
|
||||||
globalAccess, organizationId,
|
globalAccess, schoolId,
|
||||||
);
|
);
|
||||||
|
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -428,6 +428,7 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
router.get('/:id', wrapAsync(async (req, res) => {
|
router.get('/:id', wrapAsync(async (req, res) => {
|
||||||
const payload = await AttendanceDBApi.findBy(
|
const payload = await AttendanceDBApi.findBy(
|
||||||
{ id: req.params.id },
|
{ id: req.params.id },
|
||||||
|
{ currentUser: req.currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -3,10 +3,9 @@ const express = require('express');
|
|||||||
|
|
||||||
const Book_loansService = require('../services/book_loans');
|
const Book_loansService = require('../services/book_loans');
|
||||||
const Book_loansDBApi = require('../db/api/book_loans');
|
const Book_loansDBApi = require('../db/api/book_loans');
|
||||||
|
const { getCurrentUserSchoolId } = require('../db/api/schoolScope');
|
||||||
const wrapAsync = require('../helpers').wrapAsync;
|
const wrapAsync = require('../helpers').wrapAsync;
|
||||||
|
|
||||||
const config = require('../config');
|
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@ -306,6 +305,7 @@ router.get('/', wrapAsync(async (req, res) => {
|
|||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -381,14 +381,14 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
|
|
||||||
const globalAccess = req.currentUser.app_role.globalAccess;
|
const globalAccess = req.currentUser.app_role.globalAccess;
|
||||||
|
|
||||||
const organizationId = req.currentUser.organization?.id
|
const schoolId = getCurrentUserSchoolId(req.currentUser);
|
||||||
|
|
||||||
|
|
||||||
const payload = await Book_loansDBApi.findAllAutocomplete(
|
const payload = await Book_loansDBApi.findAllAutocomplete(
|
||||||
req.query.query,
|
req.query.query,
|
||||||
req.query.limit,
|
req.query.limit,
|
||||||
req.query.offset,
|
req.query.offset,
|
||||||
globalAccess, organizationId,
|
globalAccess, schoolId,
|
||||||
);
|
);
|
||||||
|
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -429,6 +429,7 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
router.get('/:id', wrapAsync(async (req, res) => {
|
router.get('/:id', wrapAsync(async (req, res) => {
|
||||||
const payload = await Book_loansDBApi.findBy(
|
const payload = await Book_loansDBApi.findBy(
|
||||||
{ id: req.params.id },
|
{ id: req.params.id },
|
||||||
|
{ currentUser: req.currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -3,10 +3,9 @@ const express = require('express');
|
|||||||
|
|
||||||
const BooksService = require('../services/books');
|
const BooksService = require('../services/books');
|
||||||
const BooksDBApi = require('../db/api/books');
|
const BooksDBApi = require('../db/api/books');
|
||||||
|
const { getCurrentUserSchoolId } = require('../db/api/schoolScope');
|
||||||
const wrapAsync = require('../helpers').wrapAsync;
|
const wrapAsync = require('../helpers').wrapAsync;
|
||||||
|
|
||||||
const config = require('../config');
|
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@ -318,6 +317,7 @@ router.get('/', wrapAsync(async (req, res) => {
|
|||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -393,14 +393,14 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
|
|
||||||
const globalAccess = req.currentUser.app_role.globalAccess;
|
const globalAccess = req.currentUser.app_role.globalAccess;
|
||||||
|
|
||||||
const organizationId = req.currentUser.organization?.id
|
const schoolId = getCurrentUserSchoolId(req.currentUser);
|
||||||
|
|
||||||
|
|
||||||
const payload = await BooksDBApi.findAllAutocomplete(
|
const payload = await BooksDBApi.findAllAutocomplete(
|
||||||
req.query.query,
|
req.query.query,
|
||||||
req.query.limit,
|
req.query.limit,
|
||||||
req.query.offset,
|
req.query.offset,
|
||||||
globalAccess, organizationId,
|
globalAccess, schoolId,
|
||||||
);
|
);
|
||||||
|
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -441,6 +441,7 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
router.get('/:id', wrapAsync(async (req, res) => {
|
router.get('/:id', wrapAsync(async (req, res) => {
|
||||||
const payload = await BooksDBApi.findBy(
|
const payload = await BooksDBApi.findBy(
|
||||||
{ id: req.params.id },
|
{ id: req.params.id },
|
||||||
|
{ currentUser: req.currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -3,10 +3,9 @@ const express = require('express');
|
|||||||
|
|
||||||
const ClassesService = require('../services/classes');
|
const ClassesService = require('../services/classes');
|
||||||
const ClassesDBApi = require('../db/api/classes');
|
const ClassesDBApi = require('../db/api/classes');
|
||||||
|
const { getCurrentUserSchoolId } = require('../db/api/schoolScope');
|
||||||
const wrapAsync = require('../helpers').wrapAsync;
|
const wrapAsync = require('../helpers').wrapAsync;
|
||||||
|
|
||||||
const config = require('../config');
|
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@ -313,6 +312,7 @@ router.get('/', wrapAsync(async (req, res) => {
|
|||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -388,14 +388,14 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
|
|
||||||
const globalAccess = req.currentUser.app_role.globalAccess;
|
const globalAccess = req.currentUser.app_role.globalAccess;
|
||||||
|
|
||||||
const organizationId = req.currentUser.organization?.id
|
const schoolId = getCurrentUserSchoolId(req.currentUser);
|
||||||
|
|
||||||
|
|
||||||
const payload = await ClassesDBApi.findAllAutocomplete(
|
const payload = await ClassesDBApi.findAllAutocomplete(
|
||||||
req.query.query,
|
req.query.query,
|
||||||
req.query.limit,
|
req.query.limit,
|
||||||
req.query.offset,
|
req.query.offset,
|
||||||
globalAccess, organizationId,
|
globalAccess, schoolId,
|
||||||
);
|
);
|
||||||
|
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -436,6 +436,7 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
router.get('/:id', wrapAsync(async (req, res) => {
|
router.get('/:id', wrapAsync(async (req, res) => {
|
||||||
const payload = await ClassesDBApi.findBy(
|
const payload = await ClassesDBApi.findBy(
|
||||||
{ id: req.params.id },
|
{ id: req.params.id },
|
||||||
|
{ currentUser: req.currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -3,10 +3,9 @@ const express = require('express');
|
|||||||
|
|
||||||
const CoursesService = require('../services/courses');
|
const CoursesService = require('../services/courses');
|
||||||
const CoursesDBApi = require('../db/api/courses');
|
const CoursesDBApi = require('../db/api/courses');
|
||||||
|
const { getCurrentUserSchoolId } = require('../db/api/schoolScope');
|
||||||
const wrapAsync = require('../helpers').wrapAsync;
|
const wrapAsync = require('../helpers').wrapAsync;
|
||||||
|
|
||||||
const config = require('../config');
|
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@ -309,6 +308,7 @@ router.get('/', wrapAsync(async (req, res) => {
|
|||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -384,14 +384,14 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
|
|
||||||
const globalAccess = req.currentUser.app_role.globalAccess;
|
const globalAccess = req.currentUser.app_role.globalAccess;
|
||||||
|
|
||||||
const organizationId = req.currentUser.organization?.id
|
const schoolId = getCurrentUserSchoolId(req.currentUser);
|
||||||
|
|
||||||
|
|
||||||
const payload = await CoursesDBApi.findAllAutocomplete(
|
const payload = await CoursesDBApi.findAllAutocomplete(
|
||||||
req.query.query,
|
req.query.query,
|
||||||
req.query.limit,
|
req.query.limit,
|
||||||
req.query.offset,
|
req.query.offset,
|
||||||
globalAccess, organizationId,
|
globalAccess, schoolId,
|
||||||
);
|
);
|
||||||
|
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -432,6 +432,7 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
router.get('/:id', wrapAsync(async (req, res) => {
|
router.get('/:id', wrapAsync(async (req, res) => {
|
||||||
const payload = await CoursesDBApi.findBy(
|
const payload = await CoursesDBApi.findBy(
|
||||||
{ id: req.params.id },
|
{ id: req.params.id },
|
||||||
|
{ currentUser: req.currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -3,10 +3,9 @@ const express = require('express');
|
|||||||
|
|
||||||
const EmployeesService = require('../services/employees');
|
const EmployeesService = require('../services/employees');
|
||||||
const EmployeesDBApi = require('../db/api/employees');
|
const EmployeesDBApi = require('../db/api/employees');
|
||||||
|
const { getCurrentUserSchoolId } = require('../db/api/schoolScope');
|
||||||
const wrapAsync = require('../helpers').wrapAsync;
|
const wrapAsync = require('../helpers').wrapAsync;
|
||||||
|
|
||||||
const config = require('../config');
|
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@ -315,6 +314,7 @@ router.get('/', wrapAsync(async (req, res) => {
|
|||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -390,14 +390,14 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
|
|
||||||
const globalAccess = req.currentUser.app_role.globalAccess;
|
const globalAccess = req.currentUser.app_role.globalAccess;
|
||||||
|
|
||||||
const organizationId = req.currentUser.organization?.id
|
const schoolId = getCurrentUserSchoolId(req.currentUser);
|
||||||
|
|
||||||
|
|
||||||
const payload = await EmployeesDBApi.findAllAutocomplete(
|
const payload = await EmployeesDBApi.findAllAutocomplete(
|
||||||
req.query.query,
|
req.query.query,
|
||||||
req.query.limit,
|
req.query.limit,
|
||||||
req.query.offset,
|
req.query.offset,
|
||||||
globalAccess, organizationId,
|
globalAccess, schoolId,
|
||||||
);
|
);
|
||||||
|
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -438,6 +438,7 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
router.get('/:id', wrapAsync(async (req, res) => {
|
router.get('/:id', wrapAsync(async (req, res) => {
|
||||||
const payload = await EmployeesDBApi.findBy(
|
const payload = await EmployeesDBApi.findBy(
|
||||||
{ id: req.params.id },
|
{ id: req.params.id },
|
||||||
|
{ currentUser: req.currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -3,10 +3,9 @@ const express = require('express');
|
|||||||
|
|
||||||
const EnrollmentsService = require('../services/enrollments');
|
const EnrollmentsService = require('../services/enrollments');
|
||||||
const EnrollmentsDBApi = require('../db/api/enrollments');
|
const EnrollmentsDBApi = require('../db/api/enrollments');
|
||||||
|
const { getCurrentUserSchoolId } = require('../db/api/schoolScope');
|
||||||
const wrapAsync = require('../helpers').wrapAsync;
|
const wrapAsync = require('../helpers').wrapAsync;
|
||||||
|
|
||||||
const config = require('../config');
|
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@ -306,6 +305,7 @@ router.get('/', wrapAsync(async (req, res) => {
|
|||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -381,14 +381,14 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
|
|
||||||
const globalAccess = req.currentUser.app_role.globalAccess;
|
const globalAccess = req.currentUser.app_role.globalAccess;
|
||||||
|
|
||||||
const organizationId = req.currentUser.organization?.id
|
const schoolId = getCurrentUserSchoolId(req.currentUser);
|
||||||
|
|
||||||
|
|
||||||
const payload = await EnrollmentsDBApi.findAllAutocomplete(
|
const payload = await EnrollmentsDBApi.findAllAutocomplete(
|
||||||
req.query.query,
|
req.query.query,
|
||||||
req.query.limit,
|
req.query.limit,
|
||||||
req.query.offset,
|
req.query.offset,
|
||||||
globalAccess, organizationId,
|
globalAccess, schoolId,
|
||||||
);
|
);
|
||||||
|
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -429,6 +429,7 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
router.get('/:id', wrapAsync(async (req, res) => {
|
router.get('/:id', wrapAsync(async (req, res) => {
|
||||||
const payload = await EnrollmentsDBApi.findBy(
|
const payload = await EnrollmentsDBApi.findBy(
|
||||||
{ id: req.params.id },
|
{ id: req.params.id },
|
||||||
|
{ currentUser: req.currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,21 +1,24 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const config = require('../config');
|
|
||||||
const path = require('path');
|
|
||||||
const passport = require('passport');
|
const passport = require('passport');
|
||||||
const services = require('../services/file');
|
const services = require('../services/file');
|
||||||
|
const wrapAsync = require('../helpers').wrapAsync;
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
router.get('/download', (req, res) => {
|
router.get('/download', wrapAsync(async (req, res) => {
|
||||||
if (process.env.NODE_ENV == "production" || process.env.NEXT_PUBLIC_BACK_API) {
|
if (process.env.NODE_ENV == "production" || process.env.NEXT_PUBLIC_BACK_API) {
|
||||||
services.downloadGCloud(req, res);
|
await services.downloadGCloud(req, res);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
services.downloadLocal(req, res);
|
await services.downloadLocal(req, res);
|
||||||
}
|
}
|
||||||
});
|
}));
|
||||||
|
|
||||||
router.post('/upload/:table/:field', passport.authenticate('jwt', {session: false}), (req, res) => {
|
router.post('/upload/:table/:field', passport.authenticate('jwt', {session: false}), (req, res) => {
|
||||||
const fileName = `${req.params.table}/${req.params.field}`;
|
const fileName = services.normalizeFolder(`${req.params.table}/${req.params.field}`);
|
||||||
|
|
||||||
|
if (!fileName) {
|
||||||
|
return res.status(400).send({ message: 'Invalid upload path.' });
|
||||||
|
}
|
||||||
|
|
||||||
if (process.env.NODE_ENV == "production" || process.env.NEXT_PUBLIC_BACK_API) {
|
if (process.env.NODE_ENV == "production" || process.env.NEXT_PUBLIC_BACK_API) {
|
||||||
services.uploadGCloud(fileName, req, res);
|
services.uploadGCloud(fileName, req, res);
|
||||||
@ -29,4 +32,7 @@ router.post('/upload/:table/:field', passport.authenticate('jwt', {session: fals
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
router.use('/', require('../helpers').commonErrorHandler);
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
@ -3,10 +3,9 @@ const express = require('express');
|
|||||||
|
|
||||||
const GradesService = require('../services/grades');
|
const GradesService = require('../services/grades');
|
||||||
const GradesDBApi = require('../db/api/grades');
|
const GradesDBApi = require('../db/api/grades');
|
||||||
|
const { getCurrentUserSchoolId } = require('../db/api/schoolScope');
|
||||||
const wrapAsync = require('../helpers').wrapAsync;
|
const wrapAsync = require('../helpers').wrapAsync;
|
||||||
|
|
||||||
const config = require('../config');
|
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@ -309,6 +308,7 @@ router.get('/', wrapAsync(async (req, res) => {
|
|||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -384,14 +384,14 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
|
|
||||||
const globalAccess = req.currentUser.app_role.globalAccess;
|
const globalAccess = req.currentUser.app_role.globalAccess;
|
||||||
|
|
||||||
const organizationId = req.currentUser.organization?.id
|
const schoolId = getCurrentUserSchoolId(req.currentUser);
|
||||||
|
|
||||||
|
|
||||||
const payload = await GradesDBApi.findAllAutocomplete(
|
const payload = await GradesDBApi.findAllAutocomplete(
|
||||||
req.query.query,
|
req.query.query,
|
||||||
req.query.limit,
|
req.query.limit,
|
||||||
req.query.offset,
|
req.query.offset,
|
||||||
globalAccess, organizationId,
|
globalAccess, schoolId,
|
||||||
);
|
);
|
||||||
|
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -432,6 +432,7 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
router.get('/:id', wrapAsync(async (req, res) => {
|
router.get('/:id', wrapAsync(async (req, res) => {
|
||||||
const payload = await GradesDBApi.findBy(
|
const payload = await GradesDBApi.findBy(
|
||||||
{ id: req.params.id },
|
{ id: req.params.id },
|
||||||
|
{ currentUser: req.currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -3,10 +3,9 @@ const express = require('express');
|
|||||||
|
|
||||||
const GuardiansService = require('../services/guardians');
|
const GuardiansService = require('../services/guardians');
|
||||||
const GuardiansDBApi = require('../db/api/guardians');
|
const GuardiansDBApi = require('../db/api/guardians');
|
||||||
|
const { getCurrentUserSchoolId } = require('../db/api/schoolScope');
|
||||||
const wrapAsync = require('../helpers').wrapAsync;
|
const wrapAsync = require('../helpers').wrapAsync;
|
||||||
|
|
||||||
const config = require('../config');
|
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@ -312,6 +311,7 @@ router.get('/', wrapAsync(async (req, res) => {
|
|||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -387,14 +387,14 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
|
|
||||||
const globalAccess = req.currentUser.app_role.globalAccess;
|
const globalAccess = req.currentUser.app_role.globalAccess;
|
||||||
|
|
||||||
const organizationId = req.currentUser.organization?.id
|
const schoolId = getCurrentUserSchoolId(req.currentUser);
|
||||||
|
|
||||||
|
|
||||||
const payload = await GuardiansDBApi.findAllAutocomplete(
|
const payload = await GuardiansDBApi.findAllAutocomplete(
|
||||||
req.query.query,
|
req.query.query,
|
||||||
req.query.limit,
|
req.query.limit,
|
||||||
req.query.offset,
|
req.query.offset,
|
||||||
globalAccess, organizationId,
|
globalAccess, schoolId,
|
||||||
);
|
);
|
||||||
|
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -435,6 +435,7 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
router.get('/:id', wrapAsync(async (req, res) => {
|
router.get('/:id', wrapAsync(async (req, res) => {
|
||||||
const payload = await GuardiansDBApi.findBy(
|
const payload = await GuardiansDBApi.findBy(
|
||||||
{ id: req.params.id },
|
{ id: req.params.id },
|
||||||
|
{ currentUser: req.currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -3,10 +3,9 @@ const express = require('express');
|
|||||||
|
|
||||||
const InvoicesService = require('../services/invoices');
|
const InvoicesService = require('../services/invoices');
|
||||||
const InvoicesDBApi = require('../db/api/invoices');
|
const InvoicesDBApi = require('../db/api/invoices');
|
||||||
|
const { getCurrentUserSchoolId } = require('../db/api/schoolScope');
|
||||||
const wrapAsync = require('../helpers').wrapAsync;
|
const wrapAsync = require('../helpers').wrapAsync;
|
||||||
|
|
||||||
const config = require('../config');
|
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@ -312,6 +311,7 @@ router.get('/', wrapAsync(async (req, res) => {
|
|||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -387,14 +387,14 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
|
|
||||||
const globalAccess = req.currentUser.app_role.globalAccess;
|
const globalAccess = req.currentUser.app_role.globalAccess;
|
||||||
|
|
||||||
const organizationId = req.currentUser.organization?.id
|
const schoolId = getCurrentUserSchoolId(req.currentUser);
|
||||||
|
|
||||||
|
|
||||||
const payload = await InvoicesDBApi.findAllAutocomplete(
|
const payload = await InvoicesDBApi.findAllAutocomplete(
|
||||||
req.query.query,
|
req.query.query,
|
||||||
req.query.limit,
|
req.query.limit,
|
||||||
req.query.offset,
|
req.query.offset,
|
||||||
globalAccess, organizationId,
|
globalAccess, schoolId,
|
||||||
);
|
);
|
||||||
|
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -435,6 +435,7 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
router.get('/:id', wrapAsync(async (req, res) => {
|
router.get('/:id', wrapAsync(async (req, res) => {
|
||||||
const payload = await InvoicesDBApi.findBy(
|
const payload = await InvoicesDBApi.findBy(
|
||||||
{ id: req.params.id },
|
{ id: req.params.id },
|
||||||
|
{ currentUser: req.currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,109 @@ const router = express.Router();
|
|||||||
const sjs = require('sequelize-json-schema');
|
const sjs = require('sequelize-json-schema');
|
||||||
const { getWidget, askGpt } = require('../services/openai');
|
const { getWidget, askGpt } = require('../services/openai');
|
||||||
const { LocalAIApi } = require('../ai/LocalAIApi');
|
const { LocalAIApi } = require('../ai/LocalAIApi');
|
||||||
|
const ForbiddenError = require('../services/notifications/errors/forbidden');
|
||||||
|
const { checkPermissions } = require('../middlewares/check-permissions');
|
||||||
|
|
||||||
|
|
||||||
|
const WIDGET_CUSTOMIZATION_KEY = 'widgets';
|
||||||
|
const UUID_REGEX = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
||||||
|
|
||||||
|
function badRequest(message) {
|
||||||
|
const error = new Error(message);
|
||||||
|
error.code = 400;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeWidgetKey(key) {
|
||||||
|
if (key !== WIDGET_CUSTOMIZATION_KEY) {
|
||||||
|
throw badRequest('Invalid role customization key.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeUuid(value, label) {
|
||||||
|
if (typeof value !== 'string' || !UUID_REGEX.test(value)) {
|
||||||
|
throw badRequest(`${label} must be a valid UUID.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeText(value, label, maxLength) {
|
||||||
|
if (typeof value !== 'string' || !value.trim()) {
|
||||||
|
throw badRequest(`${label} is required.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalized = value.trim();
|
||||||
|
if (normalized.length > maxLength) {
|
||||||
|
throw badRequest(`${label} is too long. Maximum length is ${maxLength} characters.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeNumberOption(value, defaultValue, minValue, maxValue) {
|
||||||
|
const parsed = Number(value);
|
||||||
|
if (!Number.isFinite(parsed)) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.min(Math.max(parsed, minValue), maxValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeAiProxyOptions(options = {}) {
|
||||||
|
return {
|
||||||
|
poll_interval: normalizeNumberOption(options.poll_interval, 5, 1, 30),
|
||||||
|
poll_timeout: normalizeNumberOption(options.poll_timeout, 300, 5, 300),
|
||||||
|
timeout: normalizeNumberOption(options.timeout, 30, 5, 60),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertGlobalRoleAccess(currentUser) {
|
||||||
|
if (!currentUser?.app_role?.globalAccess) {
|
||||||
|
throw new ForbiddenError('auth.forbidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function hasRolePermission(currentUser, permission) {
|
||||||
|
if (!currentUser) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const customPermissions = Array.isArray(currentUser.custom_permissions)
|
||||||
|
? currentUser.custom_permissions
|
||||||
|
: [];
|
||||||
|
|
||||||
|
if (customPermissions.find((cp) => cp.name === permission)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!currentUser.app_role) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const permissions = typeof currentUser.app_role.getPermissions === 'function'
|
||||||
|
? await currentUser.app_role.getPermissions()
|
||||||
|
: currentUser.app_role.permissions || [];
|
||||||
|
|
||||||
|
return !!permissions.find((p) => p.name === permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function assertCanReadRoleWidgets(roleId, currentUser) {
|
||||||
|
if (roleId === currentUser?.app_role?.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(await hasRolePermission(currentUser, 'READ_ROLES'))) {
|
||||||
|
throw new ForbiddenError('auth.forbidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function canGenerateRoleWidgets(currentUser) {
|
||||||
|
return !!currentUser?.app_role?.globalAccess
|
||||||
|
&& await hasRolePermission(currentUser, 'UPDATE_ROLES');
|
||||||
|
}
|
||||||
|
|
||||||
const loadRolesModules = () => {
|
const loadRolesModules = () => {
|
||||||
try {
|
try {
|
||||||
@ -71,12 +174,17 @@ const loadRolesModules = () => {
|
|||||||
|
|
||||||
router.delete(
|
router.delete(
|
||||||
'/roles-info/:infoId',
|
'/roles-info/:infoId',
|
||||||
|
checkPermissions('UPDATE_ROLES'),
|
||||||
wrapAsync(async (req, res) => {
|
wrapAsync(async (req, res) => {
|
||||||
|
assertGlobalRoleAccess(req.currentUser);
|
||||||
const { RolesService } = loadRolesModules();
|
const { RolesService } = loadRolesModules();
|
||||||
|
const key = normalizeWidgetKey(req.query.key);
|
||||||
|
const infoId = normalizeUuid(req.query.infoId || req.params.infoId, 'Widget ID');
|
||||||
|
const roleId = normalizeUuid(req.query.roleId, 'Role ID');
|
||||||
const role = await RolesService.removeRoleInfoById(
|
const role = await RolesService.removeRoleInfoById(
|
||||||
req.query.infoId,
|
infoId,
|
||||||
req.query.roleId,
|
roleId,
|
||||||
req.query.key,
|
key,
|
||||||
req.currentUser,
|
req.currentUser,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -131,33 +239,46 @@ router.get(
|
|||||||
'/info-by-key',
|
'/info-by-key',
|
||||||
wrapAsync(async (req, res) => {
|
wrapAsync(async (req, res) => {
|
||||||
const { RolesService, RolesDBApi } = loadRolesModules();
|
const { RolesService, RolesDBApi } = loadRolesModules();
|
||||||
const roleId = req.query.roleId;
|
|
||||||
const key = req.query.key;
|
|
||||||
const currentUser = req.currentUser;
|
const currentUser = req.currentUser;
|
||||||
|
const key = normalizeWidgetKey(req.query.key);
|
||||||
|
const roleId = normalizeUuid(req.query.roleId || currentUser?.app_role?.id, 'Role ID');
|
||||||
|
|
||||||
|
await assertCanReadRoleWidgets(roleId, currentUser);
|
||||||
|
|
||||||
|
const role = await RolesDBApi.findBy({ id: roleId });
|
||||||
|
if (!role) {
|
||||||
|
return res.status(404).send('Role not found');
|
||||||
|
}
|
||||||
|
|
||||||
let info = await RolesService.getRoleInfoByKey(
|
let info = await RolesService.getRoleInfoByKey(
|
||||||
key,
|
key,
|
||||||
roleId,
|
roleId,
|
||||||
currentUser,
|
currentUser,
|
||||||
);
|
);
|
||||||
const role = await RolesDBApi.findBy({ id: roleId });
|
|
||||||
if (!role?.role_customization) {
|
if (!role.role_customization && await canGenerateRoleWidgets(currentUser)) {
|
||||||
await Promise.all(["pie", "bar"].map(async (e) => {
|
const schema = await sjs.getSequelizeSchema(db.sequelize, {});
|
||||||
const schema = await sjs.getSequelizeSchema(db.sequelize, {});
|
const widgetResults = await Promise.allSettled(['pie', 'bar'].map(async (chartType) => {
|
||||||
const payload = {
|
const payload = {
|
||||||
description: `Create some cool ${e} chart`,
|
description: `Create some cool ${chartType} chart`,
|
||||||
modelDefinition: schema.definitions,
|
modelDefinition: schema.definitions,
|
||||||
};
|
};
|
||||||
const widgetId = await getWidget(payload, currentUser?.id, roleId);
|
const widgetId = await getWidget(payload);
|
||||||
if (widgetId) {
|
if (typeof widgetId === 'string') {
|
||||||
await RolesService.addRoleInfo(
|
await RolesService.addRoleInfo(
|
||||||
roleId,
|
roleId,
|
||||||
currentUser?.id,
|
currentUser?.id,
|
||||||
'widgets',
|
WIDGET_CUSTOMIZATION_KEY,
|
||||||
widgetId,
|
widgetId,
|
||||||
req.currentUser,
|
req.currentUser,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}))
|
}));
|
||||||
|
|
||||||
|
widgetResults
|
||||||
|
.filter((result) => result.status === 'rejected')
|
||||||
|
.forEach((result) => console.error('Default widget creation failed:', result.reason));
|
||||||
|
|
||||||
info = await RolesService.getRoleInfoByKey(
|
info = await RolesService.getRoleInfoByKey(
|
||||||
key,
|
key,
|
||||||
roleId,
|
roleId,
|
||||||
@ -170,9 +291,13 @@ router.get(
|
|||||||
|
|
||||||
router.post(
|
router.post(
|
||||||
'/create_widget',
|
'/create_widget',
|
||||||
|
checkPermissions('UPDATE_ROLES'),
|
||||||
wrapAsync(async (req, res) => {
|
wrapAsync(async (req, res) => {
|
||||||
|
assertGlobalRoleAccess(req.currentUser);
|
||||||
const { RolesService } = loadRolesModules();
|
const { RolesService } = loadRolesModules();
|
||||||
const { description, userId, roleId } = req.body;
|
const { userId } = req.body || {};
|
||||||
|
const description = normalizeText(req.body?.description, 'Description', 1000);
|
||||||
|
const roleId = normalizeUuid(req.body?.roleId, 'Role ID');
|
||||||
|
|
||||||
const currentUser = req.currentUser;
|
const currentUser = req.currentUser;
|
||||||
const schema = await sjs.getSequelizeSchema(db.sequelize, {});
|
const schema = await sjs.getSequelizeSchema(db.sequelize, {});
|
||||||
@ -181,13 +306,13 @@ router.post(
|
|||||||
modelDefinition: schema.definitions,
|
modelDefinition: schema.definitions,
|
||||||
};
|
};
|
||||||
|
|
||||||
const widgetId = await getWidget(payload, userId, roleId);
|
const widgetId = await getWidget(payload);
|
||||||
|
|
||||||
if (widgetId) {
|
if (typeof widgetId === 'string') {
|
||||||
await RolesService.addRoleInfo(
|
await RolesService.addRoleInfo(
|
||||||
roleId,
|
roleId,
|
||||||
userId,
|
userId,
|
||||||
'widgets',
|
WIDGET_CUSTOMIZATION_KEY,
|
||||||
widgetId,
|
widgetId,
|
||||||
currentUser,
|
currentUser,
|
||||||
);
|
);
|
||||||
@ -247,9 +372,10 @@ router.post(
|
|||||||
'/response',
|
'/response',
|
||||||
wrapAsync(async (req, res) => {
|
wrapAsync(async (req, res) => {
|
||||||
const body = req.body || {};
|
const body = req.body || {};
|
||||||
const options = body.options || {};
|
const options = normalizeAiProxyOptions(body.options || {});
|
||||||
const payload = { ...body };
|
const payload = { ...body };
|
||||||
delete payload.options;
|
delete payload.options;
|
||||||
|
delete payload.project_uuid;
|
||||||
|
|
||||||
const response = await LocalAIApi.createResponse(payload, options);
|
const response = await LocalAIApi.createResponse(payload, options);
|
||||||
|
|
||||||
@ -306,13 +432,7 @@ router.post(
|
|||||||
router.post(
|
router.post(
|
||||||
'/ask-gpt',
|
'/ask-gpt',
|
||||||
wrapAsync(async (req, res) => {
|
wrapAsync(async (req, res) => {
|
||||||
const { prompt } = req.body;
|
const prompt = normalizeText(req.body?.prompt, 'Prompt', 4000);
|
||||||
if (!prompt) {
|
|
||||||
return res.status(400).send({
|
|
||||||
success: false,
|
|
||||||
error: 'Prompt is required',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await askGpt(prompt);
|
const response = await askGpt(prompt);
|
||||||
|
|
||||||
@ -325,4 +445,6 @@ router.post(
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
router.use('/', require('../helpers').commonErrorHandler);
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
@ -3,10 +3,9 @@ const express = require('express');
|
|||||||
|
|
||||||
const PaymentsService = require('../services/payments');
|
const PaymentsService = require('../services/payments');
|
||||||
const PaymentsDBApi = require('../db/api/payments');
|
const PaymentsDBApi = require('../db/api/payments');
|
||||||
|
const { getCurrentUserSchoolId } = require('../db/api/schoolScope');
|
||||||
const wrapAsync = require('../helpers').wrapAsync;
|
const wrapAsync = require('../helpers').wrapAsync;
|
||||||
|
|
||||||
const config = require('../config');
|
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@ -309,6 +308,7 @@ router.get('/', wrapAsync(async (req, res) => {
|
|||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -384,14 +384,14 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
|
|
||||||
const globalAccess = req.currentUser.app_role.globalAccess;
|
const globalAccess = req.currentUser.app_role.globalAccess;
|
||||||
|
|
||||||
const organizationId = req.currentUser.organization?.id
|
const schoolId = getCurrentUserSchoolId(req.currentUser);
|
||||||
|
|
||||||
|
|
||||||
const payload = await PaymentsDBApi.findAllAutocomplete(
|
const payload = await PaymentsDBApi.findAllAutocomplete(
|
||||||
req.query.query,
|
req.query.query,
|
||||||
req.query.limit,
|
req.query.limit,
|
||||||
req.query.offset,
|
req.query.offset,
|
||||||
globalAccess, organizationId,
|
globalAccess, schoolId,
|
||||||
);
|
);
|
||||||
|
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -432,6 +432,7 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
router.get('/:id', wrapAsync(async (req, res) => {
|
router.get('/:id', wrapAsync(async (req, res) => {
|
||||||
const payload = await PaymentsDBApi.findBy(
|
const payload = await PaymentsDBApi.findBy(
|
||||||
{ id: req.params.id },
|
{ id: req.params.id },
|
||||||
|
{ currentUser: req.currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -301,6 +301,7 @@ router.get('/', wrapAsync(async (req, res) => {
|
|||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
|
|||||||
@ -3,10 +3,9 @@ const express = require('express');
|
|||||||
|
|
||||||
const ProductsService = require('../services/products');
|
const ProductsService = require('../services/products');
|
||||||
const ProductsDBApi = require('../db/api/products');
|
const ProductsDBApi = require('../db/api/products');
|
||||||
|
const { getCurrentUserSchoolId } = require('../db/api/schoolScope');
|
||||||
const wrapAsync = require('../helpers').wrapAsync;
|
const wrapAsync = require('../helpers').wrapAsync;
|
||||||
|
|
||||||
const config = require('../config');
|
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@ -315,6 +314,7 @@ router.get('/', wrapAsync(async (req, res) => {
|
|||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -390,14 +390,14 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
|
|
||||||
const globalAccess = req.currentUser.app_role.globalAccess;
|
const globalAccess = req.currentUser.app_role.globalAccess;
|
||||||
|
|
||||||
const organizationId = req.currentUser.organization?.id
|
const schoolId = getCurrentUserSchoolId(req.currentUser);
|
||||||
|
|
||||||
|
|
||||||
const payload = await ProductsDBApi.findAllAutocomplete(
|
const payload = await ProductsDBApi.findAllAutocomplete(
|
||||||
req.query.query,
|
req.query.query,
|
||||||
req.query.limit,
|
req.query.limit,
|
||||||
req.query.offset,
|
req.query.offset,
|
||||||
globalAccess, organizationId,
|
globalAccess, schoolId,
|
||||||
);
|
);
|
||||||
|
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -438,6 +438,7 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
router.get('/:id', wrapAsync(async (req, res) => {
|
router.get('/:id', wrapAsync(async (req, res) => {
|
||||||
const payload = await ProductsDBApi.findBy(
|
const payload = await ProductsDBApi.findBy(
|
||||||
{ id: req.params.id },
|
{ id: req.params.id },
|
||||||
|
{ currentUser: req.currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -5,8 +5,6 @@ const RolesService = require('../services/roles');
|
|||||||
const RolesDBApi = require('../db/api/roles');
|
const RolesDBApi = require('../db/api/roles');
|
||||||
const wrapAsync = require('../helpers').wrapAsync;
|
const wrapAsync = require('../helpers').wrapAsync;
|
||||||
|
|
||||||
const config = require('../config');
|
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@ -305,6 +303,7 @@ router.get('/', wrapAsync(async (req, res) => {
|
|||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
|
|||||||
@ -3,10 +3,9 @@ const express = require('express');
|
|||||||
|
|
||||||
const SchoolsService = require('../services/schools');
|
const SchoolsService = require('../services/schools');
|
||||||
const SchoolsDBApi = require('../db/api/schools');
|
const SchoolsDBApi = require('../db/api/schools');
|
||||||
|
const { getCurrentUserSchoolId } = require('../db/api/schoolScope');
|
||||||
const wrapAsync = require('../helpers').wrapAsync;
|
const wrapAsync = require('../helpers').wrapAsync;
|
||||||
|
|
||||||
const config = require('../config');
|
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@ -31,9 +30,22 @@ router.use(checkCrudPermissions('schools'));
|
|||||||
* name:
|
* name:
|
||||||
* type: string
|
* type: string
|
||||||
* default: name
|
* default: name
|
||||||
|
* nif:
|
||||||
|
* type: string
|
||||||
|
* phone:
|
||||||
|
* type: string
|
||||||
|
* email:
|
||||||
|
* type: string
|
||||||
|
* province:
|
||||||
|
* type: string
|
||||||
|
* municipality:
|
||||||
|
* type: string
|
||||||
|
* address:
|
||||||
|
* type: string
|
||||||
|
* logoUrl:
|
||||||
|
* type: string
|
||||||
|
* status:
|
||||||
|
* type: string
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -292,11 +304,7 @@ router.get('/', wrapAsync(async (req, res) => {
|
|||||||
req.query, globalAccess, { currentUser }
|
req.query, globalAccess, { currentUser }
|
||||||
);
|
);
|
||||||
if (filetype && filetype === 'csv') {
|
if (filetype && filetype === 'csv') {
|
||||||
const fields = ['id','name',
|
const fields = ['id','name','nif','phone','email','province','municipality','address','logoUrl','status'];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
];
|
|
||||||
const opts = { fields };
|
const opts = { fields };
|
||||||
try {
|
try {
|
||||||
const csv = parse(payload.rows, opts);
|
const csv = parse(payload.rows, opts);
|
||||||
@ -305,6 +313,7 @@ router.get('/', wrapAsync(async (req, res) => {
|
|||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -380,14 +389,14 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
|
|
||||||
const globalAccess = req.currentUser.app_role.globalAccess;
|
const globalAccess = req.currentUser.app_role.globalAccess;
|
||||||
|
|
||||||
const organizationId = req.currentUser.organization?.id
|
const schoolId = getCurrentUserSchoolId(req.currentUser);
|
||||||
|
|
||||||
|
|
||||||
const payload = await SchoolsDBApi.findAllAutocomplete(
|
const payload = await SchoolsDBApi.findAllAutocomplete(
|
||||||
req.query.query,
|
req.query.query,
|
||||||
req.query.limit,
|
req.query.limit,
|
||||||
req.query.offset,
|
req.query.offset,
|
||||||
globalAccess, organizationId,
|
globalAccess, schoolId,
|
||||||
);
|
);
|
||||||
|
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -428,6 +437,7 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
router.get('/:id', wrapAsync(async (req, res) => {
|
router.get('/:id', wrapAsync(async (req, res) => {
|
||||||
const payload = await SchoolsDBApi.findBy(
|
const payload = await SchoolsDBApi.findBy(
|
||||||
{ id: req.params.id },
|
{ id: req.params.id },
|
||||||
|
{ currentUser: req.currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const SearchService = require('../services/search');
|
const SearchService = require('../services/search');
|
||||||
|
const wrapAsync = require('../helpers').wrapAsync;
|
||||||
const config = require('../config');
|
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@ -35,22 +33,14 @@ router.use(checkCrudPermissions('search'));
|
|||||||
* description: Internal server error
|
* description: Internal server error
|
||||||
*/
|
*/
|
||||||
|
|
||||||
router.post('/', async (req, res) => {
|
router.post('/', wrapAsync(async (req, res) => {
|
||||||
const { searchQuery , organizationId} = req.body;
|
const { searchQuery } = req.body || {};
|
||||||
|
const globalAccess = !!req.currentUser?.app_role?.globalAccess;
|
||||||
const globalAccess = req.currentUser.app_role.globalAccess;
|
|
||||||
|
|
||||||
if (!searchQuery) {
|
|
||||||
return res.status(400).json({ error: 'Please enter a search query' });
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const foundMatches = await SearchService.search(searchQuery, req.currentUser , organizationId, globalAccess,);
|
|
||||||
res.json(foundMatches);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Internal Server Error', error);
|
|
||||||
res.status(500).json({ error: 'Internal Server Error' });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = router;
|
const foundMatches = await SearchService.search(searchQuery, req.currentUser, globalAccess);
|
||||||
|
res.json(foundMatches);
|
||||||
|
}));
|
||||||
|
|
||||||
|
router.use('/', require('../helpers').commonErrorHandler);
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const db = require('../db/models');
|
|
||||||
const wrapAsync = require('../helpers').wrapAsync;
|
const wrapAsync = require('../helpers').wrapAsync;
|
||||||
|
const ForbiddenError = require('../services/notifications/errors/forbidden');
|
||||||
|
const { executeReadOnlySelect } = require('../services/sqlSafety');
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@ -30,32 +31,27 @@ const router = express.Router();
|
|||||||
* description: Invalid SQL
|
* description: Invalid SQL
|
||||||
* 401:
|
* 401:
|
||||||
* $ref: "#/components/responses/UnauthorizedError"
|
* $ref: "#/components/responses/UnauthorizedError"
|
||||||
|
* 403:
|
||||||
|
* description: Requires global access
|
||||||
* 500:
|
* 500:
|
||||||
* description: Internal server error
|
* description: Internal server error
|
||||||
*/
|
*/
|
||||||
router.post(
|
router.post(
|
||||||
'/',
|
'/',
|
||||||
wrapAsync(async (req, res) => {
|
wrapAsync(async (req, res) => {
|
||||||
const { sql } = req.body;
|
if (!req.currentUser?.app_role?.globalAccess) {
|
||||||
if (typeof sql !== 'string' || !sql.trim()) {
|
throw new ForbiddenError('auth.forbidden');
|
||||||
return res.status(400).json({ error: 'SQL is required' });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const normalized = sql.trim().replace(/;+\s*$/, '');
|
const body = req.body || {};
|
||||||
if (!/^select\b/i.test(normalized)) {
|
const rows = await executeReadOnlySelect(body.sql, {
|
||||||
return res.status(400).json({ error: 'Only SELECT statements are allowed' });
|
limit: body.limit,
|
||||||
}
|
|
||||||
|
|
||||||
if (normalized.includes(';')) {
|
|
||||||
return res.status(400).json({ error: 'Only a single SELECT statement is allowed' });
|
|
||||||
}
|
|
||||||
|
|
||||||
const rows = await db.sequelize.query(normalized, {
|
|
||||||
type: db.Sequelize.QueryTypes.SELECT,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.status(200).json({ rows });
|
return res.status(200).json({ rows });
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
router.use('/', require('../helpers').commonErrorHandler);
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
@ -3,10 +3,9 @@ const express = require('express');
|
|||||||
|
|
||||||
const Student_guardiansService = require('../services/student_guardians');
|
const Student_guardiansService = require('../services/student_guardians');
|
||||||
const Student_guardiansDBApi = require('../db/api/student_guardians');
|
const Student_guardiansDBApi = require('../db/api/student_guardians');
|
||||||
|
const { getCurrentUserSchoolId } = require('../db/api/schoolScope');
|
||||||
const wrapAsync = require('../helpers').wrapAsync;
|
const wrapAsync = require('../helpers').wrapAsync;
|
||||||
|
|
||||||
const config = require('../config');
|
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@ -303,6 +302,7 @@ router.get('/', wrapAsync(async (req, res) => {
|
|||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -378,14 +378,14 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
|
|
||||||
const globalAccess = req.currentUser.app_role.globalAccess;
|
const globalAccess = req.currentUser.app_role.globalAccess;
|
||||||
|
|
||||||
const organizationId = req.currentUser.organization?.id
|
const schoolId = getCurrentUserSchoolId(req.currentUser);
|
||||||
|
|
||||||
|
|
||||||
const payload = await Student_guardiansDBApi.findAllAutocomplete(
|
const payload = await Student_guardiansDBApi.findAllAutocomplete(
|
||||||
req.query.query,
|
req.query.query,
|
||||||
req.query.limit,
|
req.query.limit,
|
||||||
req.query.offset,
|
req.query.offset,
|
||||||
globalAccess, organizationId,
|
globalAccess, schoolId,
|
||||||
);
|
);
|
||||||
|
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -426,6 +426,7 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
router.get('/:id', wrapAsync(async (req, res) => {
|
router.get('/:id', wrapAsync(async (req, res) => {
|
||||||
const payload = await Student_guardiansDBApi.findBy(
|
const payload = await Student_guardiansDBApi.findBy(
|
||||||
{ id: req.params.id },
|
{ id: req.params.id },
|
||||||
|
{ currentUser: req.currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -3,10 +3,9 @@ const express = require('express');
|
|||||||
|
|
||||||
const StudentsService = require('../services/students');
|
const StudentsService = require('../services/students');
|
||||||
const StudentsDBApi = require('../db/api/students');
|
const StudentsDBApi = require('../db/api/students');
|
||||||
|
const { getCurrentUserSchoolId } = require('../db/api/schoolScope');
|
||||||
const wrapAsync = require('../helpers').wrapAsync;
|
const wrapAsync = require('../helpers').wrapAsync;
|
||||||
|
|
||||||
const config = require('../config');
|
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@ -322,6 +321,7 @@ router.get('/', wrapAsync(async (req, res) => {
|
|||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -397,14 +397,14 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
|
|
||||||
const globalAccess = req.currentUser.app_role.globalAccess;
|
const globalAccess = req.currentUser.app_role.globalAccess;
|
||||||
|
|
||||||
const organizationId = req.currentUser.organization?.id
|
const schoolId = getCurrentUserSchoolId(req.currentUser);
|
||||||
|
|
||||||
|
|
||||||
const payload = await StudentsDBApi.findAllAutocomplete(
|
const payload = await StudentsDBApi.findAllAutocomplete(
|
||||||
req.query.query,
|
req.query.query,
|
||||||
req.query.limit,
|
req.query.limit,
|
||||||
req.query.offset,
|
req.query.offset,
|
||||||
globalAccess, organizationId,
|
globalAccess, schoolId,
|
||||||
);
|
);
|
||||||
|
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -445,6 +445,7 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
router.get('/:id', wrapAsync(async (req, res) => {
|
router.get('/:id', wrapAsync(async (req, res) => {
|
||||||
const payload = await StudentsDBApi.findBy(
|
const payload = await StudentsDBApi.findBy(
|
||||||
{ id: req.params.id },
|
{ id: req.params.id },
|
||||||
|
{ currentUser: req.currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -3,10 +3,9 @@ const express = require('express');
|
|||||||
|
|
||||||
const SubjectsService = require('../services/subjects');
|
const SubjectsService = require('../services/subjects');
|
||||||
const SubjectsDBApi = require('../db/api/subjects');
|
const SubjectsDBApi = require('../db/api/subjects');
|
||||||
|
const { getCurrentUserSchoolId } = require('../db/api/schoolScope');
|
||||||
const wrapAsync = require('../helpers').wrapAsync;
|
const wrapAsync = require('../helpers').wrapAsync;
|
||||||
|
|
||||||
const config = require('../config');
|
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@ -306,6 +305,7 @@ router.get('/', wrapAsync(async (req, res) => {
|
|||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -381,14 +381,14 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
|
|
||||||
const globalAccess = req.currentUser.app_role.globalAccess;
|
const globalAccess = req.currentUser.app_role.globalAccess;
|
||||||
|
|
||||||
const organizationId = req.currentUser.organization?.id
|
const schoolId = getCurrentUserSchoolId(req.currentUser);
|
||||||
|
|
||||||
|
|
||||||
const payload = await SubjectsDBApi.findAllAutocomplete(
|
const payload = await SubjectsDBApi.findAllAutocomplete(
|
||||||
req.query.query,
|
req.query.query,
|
||||||
req.query.limit,
|
req.query.limit,
|
||||||
req.query.offset,
|
req.query.offset,
|
||||||
globalAccess, organizationId,
|
globalAccess, schoolId,
|
||||||
);
|
);
|
||||||
|
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -429,6 +429,7 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
router.get('/:id', wrapAsync(async (req, res) => {
|
router.get('/:id', wrapAsync(async (req, res) => {
|
||||||
const payload = await SubjectsDBApi.findBy(
|
const payload = await SubjectsDBApi.findBy(
|
||||||
{ id: req.params.id },
|
{ id: req.params.id },
|
||||||
|
{ currentUser: req.currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -3,10 +3,9 @@ const express = require('express');
|
|||||||
|
|
||||||
const TeachersService = require('../services/teachers');
|
const TeachersService = require('../services/teachers');
|
||||||
const TeachersDBApi = require('../db/api/teachers');
|
const TeachersDBApi = require('../db/api/teachers');
|
||||||
|
const { getCurrentUserSchoolId } = require('../db/api/schoolScope');
|
||||||
const wrapAsync = require('../helpers').wrapAsync;
|
const wrapAsync = require('../helpers').wrapAsync;
|
||||||
|
|
||||||
const config = require('../config');
|
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@ -315,6 +314,7 @@ router.get('/', wrapAsync(async (req, res) => {
|
|||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -390,14 +390,14 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
|
|
||||||
const globalAccess = req.currentUser.app_role.globalAccess;
|
const globalAccess = req.currentUser.app_role.globalAccess;
|
||||||
|
|
||||||
const organizationId = req.currentUser.organization?.id
|
const schoolId = getCurrentUserSchoolId(req.currentUser);
|
||||||
|
|
||||||
|
|
||||||
const payload = await TeachersDBApi.findAllAutocomplete(
|
const payload = await TeachersDBApi.findAllAutocomplete(
|
||||||
req.query.query,
|
req.query.query,
|
||||||
req.query.limit,
|
req.query.limit,
|
||||||
req.query.offset,
|
req.query.offset,
|
||||||
globalAccess, organizationId,
|
globalAccess, schoolId,
|
||||||
);
|
);
|
||||||
|
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -438,6 +438,7 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
router.get('/:id', wrapAsync(async (req, res) => {
|
router.get('/:id', wrapAsync(async (req, res) => {
|
||||||
const payload = await TeachersDBApi.findBy(
|
const payload = await TeachersDBApi.findBy(
|
||||||
{ id: req.params.id },
|
{ id: req.params.id },
|
||||||
|
{ currentUser: req.currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -3,10 +3,9 @@ const express = require('express');
|
|||||||
|
|
||||||
const UsersService = require('../services/users');
|
const UsersService = require('../services/users');
|
||||||
const UsersDBApi = require('../db/api/users');
|
const UsersDBApi = require('../db/api/users');
|
||||||
|
const { getCurrentUserSchoolId } = require('../db/api/schoolScope');
|
||||||
const wrapAsync = require('../helpers').wrapAsync;
|
const wrapAsync = require('../helpers').wrapAsync;
|
||||||
|
|
||||||
const config = require('../config');
|
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@ -314,6 +313,7 @@ router.get('/', wrapAsync(async (req, res) => {
|
|||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -389,14 +389,14 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
|
|
||||||
const globalAccess = req.currentUser.app_role.globalAccess;
|
const globalAccess = req.currentUser.app_role.globalAccess;
|
||||||
|
|
||||||
const organizationId = req.currentUser.organization?.id
|
const schoolId = getCurrentUserSchoolId(req.currentUser);
|
||||||
|
|
||||||
|
|
||||||
const payload = await UsersDBApi.findAllAutocomplete(
|
const payload = await UsersDBApi.findAllAutocomplete(
|
||||||
req.query.query,
|
req.query.query,
|
||||||
req.query.limit,
|
req.query.limit,
|
||||||
req.query.offset,
|
req.query.offset,
|
||||||
globalAccess, organizationId,
|
globalAccess, schoolId,
|
||||||
);
|
);
|
||||||
|
|
||||||
res.status(200).send(payload);
|
res.status(200).send(payload);
|
||||||
@ -437,6 +437,7 @@ router.get('/autocomplete', async (req, res) => {
|
|||||||
router.get('/:id', wrapAsync(async (req, res) => {
|
router.get('/:id', wrapAsync(async (req, res) => {
|
||||||
const payload = await UsersDBApi.findBy(
|
const payload = await UsersDBApi.findBy(
|
||||||
{ id: req.params.id },
|
{ id: req.params.id },
|
||||||
|
{ currentUser: req.currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,7 @@
|
|||||||
const db = require('../db/models');
|
const db = require('../db/models');
|
||||||
const AssessmentsDBApi = require('../db/api/assessments');
|
const AssessmentsDBApi = require('../db/api/assessments');
|
||||||
const processFile = require("../middlewares/upload");
|
const parseImportFile = require('./importFileParser');
|
||||||
const ValidationError = require('./notifications/errors/validation');
|
const ValidationError = require('./notifications/errors/validation');
|
||||||
const csv = require('csv-parser');
|
|
||||||
const axios = require('axios');
|
|
||||||
const config = require('../config');
|
|
||||||
const stream = require('stream');
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -28,28 +24,13 @@ module.exports = class AssessmentsService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async bulkImport(req, res, sendInvitationEmails = true, host) {
|
static async bulkImport(req, res) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await processFile(req, res);
|
const results = await parseImportFile(req, res);
|
||||||
const bufferStream = new stream.PassThrough();
|
|
||||||
const results = [];
|
|
||||||
|
|
||||||
await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream
|
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
bufferStream
|
|
||||||
.pipe(csv())
|
|
||||||
.on('data', (data) => results.push(data))
|
|
||||||
.on('end', async () => {
|
|
||||||
console.log('CSV results', results);
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.on('error', (error) => reject(error));
|
|
||||||
})
|
|
||||||
|
|
||||||
await AssessmentsDBApi.bulkImport(results, {
|
await AssessmentsDBApi.bulkImport(results, {
|
||||||
transaction,
|
transaction,
|
||||||
@ -70,7 +51,7 @@ module.exports = class AssessmentsService {
|
|||||||
try {
|
try {
|
||||||
let assessments = await AssessmentsDBApi.findBy(
|
let assessments = await AssessmentsDBApi.findBy(
|
||||||
{id},
|
{id},
|
||||||
{transaction},
|
{ transaction, currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!assessments) {
|
if (!assessments) {
|
||||||
@ -95,7 +76,7 @@ module.exports = class AssessmentsService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async deleteByIds(ids, currentUser) {
|
static async deleteByIds(ids, currentUser) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|||||||
@ -1,11 +1,7 @@
|
|||||||
const db = require('../db/models');
|
const db = require('../db/models');
|
||||||
const AttendanceDBApi = require('../db/api/attendance');
|
const AttendanceDBApi = require('../db/api/attendance');
|
||||||
const processFile = require("../middlewares/upload");
|
const parseImportFile = require('./importFileParser');
|
||||||
const ValidationError = require('./notifications/errors/validation');
|
const ValidationError = require('./notifications/errors/validation');
|
||||||
const csv = require('csv-parser');
|
|
||||||
const axios = require('axios');
|
|
||||||
const config = require('../config');
|
|
||||||
const stream = require('stream');
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -28,28 +24,13 @@ module.exports = class AttendanceService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async bulkImport(req, res, sendInvitationEmails = true, host) {
|
static async bulkImport(req, res) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await processFile(req, res);
|
const results = await parseImportFile(req, res);
|
||||||
const bufferStream = new stream.PassThrough();
|
|
||||||
const results = [];
|
|
||||||
|
|
||||||
await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream
|
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
bufferStream
|
|
||||||
.pipe(csv())
|
|
||||||
.on('data', (data) => results.push(data))
|
|
||||||
.on('end', async () => {
|
|
||||||
console.log('CSV results', results);
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.on('error', (error) => reject(error));
|
|
||||||
})
|
|
||||||
|
|
||||||
await AttendanceDBApi.bulkImport(results, {
|
await AttendanceDBApi.bulkImport(results, {
|
||||||
transaction,
|
transaction,
|
||||||
@ -70,7 +51,7 @@ module.exports = class AttendanceService {
|
|||||||
try {
|
try {
|
||||||
let attendance = await AttendanceDBApi.findBy(
|
let attendance = await AttendanceDBApi.findBy(
|
||||||
{id},
|
{id},
|
||||||
{transaction},
|
{ transaction, currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!attendance) {
|
if (!attendance) {
|
||||||
@ -95,7 +76,7 @@ module.exports = class AttendanceService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async deleteByIds(ids, currentUser) {
|
static async deleteByIds(ids, currentUser) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
const UsersDBApi = require('../db/api/users');
|
const UsersDBApi = require('../db/api/users');
|
||||||
|
const db = require('../db/models');
|
||||||
const ValidationError = require('./notifications/errors/validation');
|
const ValidationError = require('./notifications/errors/validation');
|
||||||
const ForbiddenError = require('./notifications/errors/forbidden');
|
const ForbiddenError = require('./notifications/errors/forbidden');
|
||||||
const bcrypt = require('bcrypt');
|
const bcrypt = require('bcrypt');
|
||||||
@ -83,7 +84,7 @@ class Auth {
|
|||||||
return helpers.jwtSign(data);
|
return helpers.jwtSign(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async signin(email, password, options = {}) {
|
static async signin(email, password) {
|
||||||
const user = await UsersDBApi.findBy({email});
|
const user = await UsersDBApi.findBy({email});
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
@ -290,12 +291,21 @@ class Auth {
|
|||||||
try {
|
try {
|
||||||
await UsersDBApi.findBy(
|
await UsersDBApi.findBy(
|
||||||
{id: currentUser.id},
|
{id: currentUser.id},
|
||||||
{transaction},
|
{ transaction, currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const safeProfile = {
|
||||||
|
firstName: data?.firstName,
|
||||||
|
lastName: data?.lastName,
|
||||||
|
phoneNumber: data?.phoneNumber,
|
||||||
|
password: data?.password,
|
||||||
|
avatar: data?.avatar,
|
||||||
|
};
|
||||||
|
|
||||||
await UsersDBApi.update(
|
await UsersDBApi.update(
|
||||||
currentUser.id,
|
currentUser.id,
|
||||||
data,
|
safeProfile,
|
||||||
|
currentUser.app_role?.globalAccess,
|
||||||
{
|
{
|
||||||
currentUser,
|
currentUser,
|
||||||
transaction
|
transaction
|
||||||
|
|||||||
@ -1,11 +1,7 @@
|
|||||||
const db = require('../db/models');
|
const db = require('../db/models');
|
||||||
const Book_loansDBApi = require('../db/api/book_loans');
|
const Book_loansDBApi = require('../db/api/book_loans');
|
||||||
const processFile = require("../middlewares/upload");
|
const parseImportFile = require('./importFileParser');
|
||||||
const ValidationError = require('./notifications/errors/validation');
|
const ValidationError = require('./notifications/errors/validation');
|
||||||
const csv = require('csv-parser');
|
|
||||||
const axios = require('axios');
|
|
||||||
const config = require('../config');
|
|
||||||
const stream = require('stream');
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -28,28 +24,13 @@ module.exports = class Book_loansService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async bulkImport(req, res, sendInvitationEmails = true, host) {
|
static async bulkImport(req, res) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await processFile(req, res);
|
const results = await parseImportFile(req, res);
|
||||||
const bufferStream = new stream.PassThrough();
|
|
||||||
const results = [];
|
|
||||||
|
|
||||||
await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream
|
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
bufferStream
|
|
||||||
.pipe(csv())
|
|
||||||
.on('data', (data) => results.push(data))
|
|
||||||
.on('end', async () => {
|
|
||||||
console.log('CSV results', results);
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.on('error', (error) => reject(error));
|
|
||||||
})
|
|
||||||
|
|
||||||
await Book_loansDBApi.bulkImport(results, {
|
await Book_loansDBApi.bulkImport(results, {
|
||||||
transaction,
|
transaction,
|
||||||
@ -70,7 +51,7 @@ module.exports = class Book_loansService {
|
|||||||
try {
|
try {
|
||||||
let book_loans = await Book_loansDBApi.findBy(
|
let book_loans = await Book_loansDBApi.findBy(
|
||||||
{id},
|
{id},
|
||||||
{transaction},
|
{ transaction, currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!book_loans) {
|
if (!book_loans) {
|
||||||
@ -95,7 +76,7 @@ module.exports = class Book_loansService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async deleteByIds(ids, currentUser) {
|
static async deleteByIds(ids, currentUser) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|||||||
@ -1,11 +1,7 @@
|
|||||||
const db = require('../db/models');
|
const db = require('../db/models');
|
||||||
const BooksDBApi = require('../db/api/books');
|
const BooksDBApi = require('../db/api/books');
|
||||||
const processFile = require("../middlewares/upload");
|
const parseImportFile = require('./importFileParser');
|
||||||
const ValidationError = require('./notifications/errors/validation');
|
const ValidationError = require('./notifications/errors/validation');
|
||||||
const csv = require('csv-parser');
|
|
||||||
const axios = require('axios');
|
|
||||||
const config = require('../config');
|
|
||||||
const stream = require('stream');
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -28,28 +24,13 @@ module.exports = class BooksService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async bulkImport(req, res, sendInvitationEmails = true, host) {
|
static async bulkImport(req, res) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await processFile(req, res);
|
const results = await parseImportFile(req, res);
|
||||||
const bufferStream = new stream.PassThrough();
|
|
||||||
const results = [];
|
|
||||||
|
|
||||||
await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream
|
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
bufferStream
|
|
||||||
.pipe(csv())
|
|
||||||
.on('data', (data) => results.push(data))
|
|
||||||
.on('end', async () => {
|
|
||||||
console.log('CSV results', results);
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.on('error', (error) => reject(error));
|
|
||||||
})
|
|
||||||
|
|
||||||
await BooksDBApi.bulkImport(results, {
|
await BooksDBApi.bulkImport(results, {
|
||||||
transaction,
|
transaction,
|
||||||
@ -70,7 +51,7 @@ module.exports = class BooksService {
|
|||||||
try {
|
try {
|
||||||
let books = await BooksDBApi.findBy(
|
let books = await BooksDBApi.findBy(
|
||||||
{id},
|
{id},
|
||||||
{transaction},
|
{ transaction, currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!books) {
|
if (!books) {
|
||||||
@ -95,7 +76,7 @@ module.exports = class BooksService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async deleteByIds(ids, currentUser) {
|
static async deleteByIds(ids, currentUser) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|||||||
@ -1,11 +1,7 @@
|
|||||||
const db = require('../db/models');
|
const db = require('../db/models');
|
||||||
const ClassesDBApi = require('../db/api/classes');
|
const ClassesDBApi = require('../db/api/classes');
|
||||||
const processFile = require("../middlewares/upload");
|
const parseImportFile = require('./importFileParser');
|
||||||
const ValidationError = require('./notifications/errors/validation');
|
const ValidationError = require('./notifications/errors/validation');
|
||||||
const csv = require('csv-parser');
|
|
||||||
const axios = require('axios');
|
|
||||||
const config = require('../config');
|
|
||||||
const stream = require('stream');
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -28,28 +24,13 @@ module.exports = class ClassesService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async bulkImport(req, res, sendInvitationEmails = true, host) {
|
static async bulkImport(req, res) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await processFile(req, res);
|
const results = await parseImportFile(req, res);
|
||||||
const bufferStream = new stream.PassThrough();
|
|
||||||
const results = [];
|
|
||||||
|
|
||||||
await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream
|
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
bufferStream
|
|
||||||
.pipe(csv())
|
|
||||||
.on('data', (data) => results.push(data))
|
|
||||||
.on('end', async () => {
|
|
||||||
console.log('CSV results', results);
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.on('error', (error) => reject(error));
|
|
||||||
})
|
|
||||||
|
|
||||||
await ClassesDBApi.bulkImport(results, {
|
await ClassesDBApi.bulkImport(results, {
|
||||||
transaction,
|
transaction,
|
||||||
@ -70,7 +51,7 @@ module.exports = class ClassesService {
|
|||||||
try {
|
try {
|
||||||
let classes = await ClassesDBApi.findBy(
|
let classes = await ClassesDBApi.findBy(
|
||||||
{id},
|
{id},
|
||||||
{transaction},
|
{ transaction, currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!classes) {
|
if (!classes) {
|
||||||
@ -95,7 +76,7 @@ module.exports = class ClassesService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async deleteByIds(ids, currentUser) {
|
static async deleteByIds(ids, currentUser) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|||||||
@ -1,11 +1,7 @@
|
|||||||
const db = require('../db/models');
|
const db = require('../db/models');
|
||||||
const CoursesDBApi = require('../db/api/courses');
|
const CoursesDBApi = require('../db/api/courses');
|
||||||
const processFile = require("../middlewares/upload");
|
const parseImportFile = require('./importFileParser');
|
||||||
const ValidationError = require('./notifications/errors/validation');
|
const ValidationError = require('./notifications/errors/validation');
|
||||||
const csv = require('csv-parser');
|
|
||||||
const axios = require('axios');
|
|
||||||
const config = require('../config');
|
|
||||||
const stream = require('stream');
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -28,28 +24,13 @@ module.exports = class CoursesService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async bulkImport(req, res, sendInvitationEmails = true, host) {
|
static async bulkImport(req, res) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await processFile(req, res);
|
const results = await parseImportFile(req, res);
|
||||||
const bufferStream = new stream.PassThrough();
|
|
||||||
const results = [];
|
|
||||||
|
|
||||||
await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream
|
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
bufferStream
|
|
||||||
.pipe(csv())
|
|
||||||
.on('data', (data) => results.push(data))
|
|
||||||
.on('end', async () => {
|
|
||||||
console.log('CSV results', results);
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.on('error', (error) => reject(error));
|
|
||||||
})
|
|
||||||
|
|
||||||
await CoursesDBApi.bulkImport(results, {
|
await CoursesDBApi.bulkImport(results, {
|
||||||
transaction,
|
transaction,
|
||||||
@ -70,7 +51,7 @@ module.exports = class CoursesService {
|
|||||||
try {
|
try {
|
||||||
let courses = await CoursesDBApi.findBy(
|
let courses = await CoursesDBApi.findBy(
|
||||||
{id},
|
{id},
|
||||||
{transaction},
|
{ transaction, currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!courses) {
|
if (!courses) {
|
||||||
@ -95,7 +76,7 @@ module.exports = class CoursesService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async deleteByIds(ids, currentUser) {
|
static async deleteByIds(ids, currentUser) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|||||||
@ -1,11 +1,7 @@
|
|||||||
const db = require('../db/models');
|
const db = require('../db/models');
|
||||||
const EmployeesDBApi = require('../db/api/employees');
|
const EmployeesDBApi = require('../db/api/employees');
|
||||||
const processFile = require("../middlewares/upload");
|
const parseImportFile = require('./importFileParser');
|
||||||
const ValidationError = require('./notifications/errors/validation');
|
const ValidationError = require('./notifications/errors/validation');
|
||||||
const csv = require('csv-parser');
|
|
||||||
const axios = require('axios');
|
|
||||||
const config = require('../config');
|
|
||||||
const stream = require('stream');
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -28,28 +24,13 @@ module.exports = class EmployeesService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async bulkImport(req, res, sendInvitationEmails = true, host) {
|
static async bulkImport(req, res) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await processFile(req, res);
|
const results = await parseImportFile(req, res);
|
||||||
const bufferStream = new stream.PassThrough();
|
|
||||||
const results = [];
|
|
||||||
|
|
||||||
await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream
|
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
bufferStream
|
|
||||||
.pipe(csv())
|
|
||||||
.on('data', (data) => results.push(data))
|
|
||||||
.on('end', async () => {
|
|
||||||
console.log('CSV results', results);
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.on('error', (error) => reject(error));
|
|
||||||
})
|
|
||||||
|
|
||||||
await EmployeesDBApi.bulkImport(results, {
|
await EmployeesDBApi.bulkImport(results, {
|
||||||
transaction,
|
transaction,
|
||||||
@ -70,7 +51,7 @@ module.exports = class EmployeesService {
|
|||||||
try {
|
try {
|
||||||
let employees = await EmployeesDBApi.findBy(
|
let employees = await EmployeesDBApi.findBy(
|
||||||
{id},
|
{id},
|
||||||
{transaction},
|
{ transaction, currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!employees) {
|
if (!employees) {
|
||||||
@ -95,7 +76,7 @@ module.exports = class EmployeesService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async deleteByIds(ids, currentUser) {
|
static async deleteByIds(ids, currentUser) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|||||||
@ -1,11 +1,7 @@
|
|||||||
const db = require('../db/models');
|
const db = require('../db/models');
|
||||||
const EnrollmentsDBApi = require('../db/api/enrollments');
|
const EnrollmentsDBApi = require('../db/api/enrollments');
|
||||||
const processFile = require("../middlewares/upload");
|
const parseImportFile = require('./importFileParser');
|
||||||
const ValidationError = require('./notifications/errors/validation');
|
const ValidationError = require('./notifications/errors/validation');
|
||||||
const csv = require('csv-parser');
|
|
||||||
const axios = require('axios');
|
|
||||||
const config = require('../config');
|
|
||||||
const stream = require('stream');
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -28,28 +24,13 @@ module.exports = class EnrollmentsService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async bulkImport(req, res, sendInvitationEmails = true, host) {
|
static async bulkImport(req, res) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await processFile(req, res);
|
const results = await parseImportFile(req, res);
|
||||||
const bufferStream = new stream.PassThrough();
|
|
||||||
const results = [];
|
|
||||||
|
|
||||||
await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream
|
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
bufferStream
|
|
||||||
.pipe(csv())
|
|
||||||
.on('data', (data) => results.push(data))
|
|
||||||
.on('end', async () => {
|
|
||||||
console.log('CSV results', results);
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.on('error', (error) => reject(error));
|
|
||||||
})
|
|
||||||
|
|
||||||
await EnrollmentsDBApi.bulkImport(results, {
|
await EnrollmentsDBApi.bulkImport(results, {
|
||||||
transaction,
|
transaction,
|
||||||
@ -70,7 +51,7 @@ module.exports = class EnrollmentsService {
|
|||||||
try {
|
try {
|
||||||
let enrollments = await EnrollmentsDBApi.findBy(
|
let enrollments = await EnrollmentsDBApi.findBy(
|
||||||
{id},
|
{id},
|
||||||
{transaction},
|
{ transaction, currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!enrollments) {
|
if (!enrollments) {
|
||||||
@ -95,7 +76,7 @@ module.exports = class EnrollmentsService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async deleteByIds(ids, currentUser) {
|
static async deleteByIds(ids, currentUser) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|||||||
@ -2,7 +2,172 @@ const formidable = require('formidable');
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const config = require('../config');
|
const config = require('../config');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { format } = require("util");
|
const crypto = require('crypto');
|
||||||
|
const db = require('../db/models');
|
||||||
|
|
||||||
|
const POSIX_SEPARATOR = '/';
|
||||||
|
|
||||||
|
const getFirstValue = (value) => {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return value[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
const normalizeStoragePath = (value) => {
|
||||||
|
if (typeof value !== 'string') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const trimmed = value.trim();
|
||||||
|
|
||||||
|
if (!trimmed || trimmed.includes('\0') || trimmed.includes('\\')) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalized = path.posix.normalize(trimmed);
|
||||||
|
|
||||||
|
if (
|
||||||
|
normalized === '.' ||
|
||||||
|
path.posix.isAbsolute(normalized) ||
|
||||||
|
normalized === '..' ||
|
||||||
|
normalized.startsWith(`..${POSIX_SEPARATOR}`) ||
|
||||||
|
normalized.split(POSIX_SEPARATOR).includes('..') ||
|
||||||
|
normalized !== trimmed
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalized;
|
||||||
|
};
|
||||||
|
|
||||||
|
const normalizeFolder = (folder) => normalizeStoragePath(folder);
|
||||||
|
|
||||||
|
const normalizePrivateUrl = (privateUrl) => normalizeStoragePath(privateUrl);
|
||||||
|
|
||||||
|
const normalizeFilename = (filename) => {
|
||||||
|
if (typeof filename !== 'string') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const trimmed = filename.trim();
|
||||||
|
|
||||||
|
if (
|
||||||
|
!trimmed ||
|
||||||
|
trimmed.includes('\0') ||
|
||||||
|
trimmed.includes(POSIX_SEPARATOR) ||
|
||||||
|
trimmed.includes('\\') ||
|
||||||
|
trimmed === '.' ||
|
||||||
|
trimmed === '..' ||
|
||||||
|
path.basename(trimmed) !== trimmed
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return trimmed;
|
||||||
|
};
|
||||||
|
|
||||||
|
const createDownloadToken = (privateUrl) => (
|
||||||
|
crypto
|
||||||
|
.createHmac('sha256', config.secret_key)
|
||||||
|
.update(privateUrl)
|
||||||
|
.digest('hex')
|
||||||
|
);
|
||||||
|
|
||||||
|
const isValidDownloadToken = (privateUrl, token) => {
|
||||||
|
if (typeof token !== 'string' || !token) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const expected = createDownloadToken(privateUrl);
|
||||||
|
const tokenBuffer = Buffer.from(token, 'hex');
|
||||||
|
const expectedBuffer = Buffer.from(expected, 'hex');
|
||||||
|
|
||||||
|
return (
|
||||||
|
tokenBuffer.length === expectedBuffer.length &&
|
||||||
|
crypto.timingSafeEqual(tokenBuffer, expectedBuffer)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildPublicDownloadUrl = (privateUrl) => (
|
||||||
|
`/api/file/download?privateUrl=${encodeURIComponent(privateUrl)}&token=${createDownloadToken(privateUrl)}`
|
||||||
|
);
|
||||||
|
|
||||||
|
const ensureKnownPrivateUrl = async (privateUrl) => {
|
||||||
|
const file = await db.file.findOne({
|
||||||
|
where: { privateUrl },
|
||||||
|
attributes: ['id'],
|
||||||
|
});
|
||||||
|
|
||||||
|
return !!file;
|
||||||
|
};
|
||||||
|
|
||||||
|
const canDownloadPrivateUrl = async (privateUrl, token) => {
|
||||||
|
if (isValidDownloadToken(privateUrl, token)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ensureKnownPrivateUrl(privateUrl);
|
||||||
|
};
|
||||||
|
|
||||||
|
const assertSafeLocalPath = (privateUrl) => {
|
||||||
|
const baseDir = path.resolve(config.uploadDir);
|
||||||
|
const targetPath = path.resolve(baseDir, privateUrl);
|
||||||
|
|
||||||
|
if (targetPath !== baseDir && !targetPath.startsWith(`${baseDir}${path.sep}`)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return targetPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
const validateFileMetadata = async (file, relation, options = {}) => {
|
||||||
|
const privateUrl = normalizePrivateUrl(file && file.privateUrl);
|
||||||
|
const expectedFolder = normalizeFolder(
|
||||||
|
`${String(relation.belongsTo)}/${String(relation.belongsToColumn)}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!privateUrl || !expectedFolder) {
|
||||||
|
const error = new Error('Invalid file path.');
|
||||||
|
error.code = 400;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const expectedPrefix = `${expectedFolder}/`;
|
||||||
|
|
||||||
|
if (!privateUrl.startsWith(expectedPrefix)) {
|
||||||
|
const error = new Error('Invalid file relation path.');
|
||||||
|
error.code = 400;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filename = privateUrl.slice(expectedPrefix.length);
|
||||||
|
|
||||||
|
if (!normalizeFilename(filename)) {
|
||||||
|
const error = new Error('Invalid file name.');
|
||||||
|
error.code = 400;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const existingFile = await db.file.findOne({
|
||||||
|
where: { privateUrl },
|
||||||
|
attributes: ['id'],
|
||||||
|
transaction: options.transaction,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (existingFile) {
|
||||||
|
const error = new Error('File already belongs to a record.');
|
||||||
|
error.code = 403;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...file,
|
||||||
|
privateUrl,
|
||||||
|
publicUrl: buildPublicDownloadUrl(privateUrl),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const ensureDirectoryExistence = (filePath) => {
|
const ensureDirectoryExistence = (filePath) => {
|
||||||
const dirname = path.dirname(filePath);
|
const dirname = path.dirname(filePath);
|
||||||
@ -36,20 +201,29 @@ const uploadLocal = (
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let uploadFolder = folder;
|
||||||
|
|
||||||
if (validations.folderIncludesAuthenticationUid) {
|
if (validations.folderIncludesAuthenticationUid) {
|
||||||
folder = folder.replace(
|
uploadFolder = uploadFolder.replace(
|
||||||
':userId',
|
':userId',
|
||||||
req.currentUser.authenticationUid,
|
req.currentUser.authenticationUid,
|
||||||
);
|
);
|
||||||
if (
|
if (
|
||||||
!req.currentUser.authenticationUid ||
|
!req.currentUser.authenticationUid ||
|
||||||
!folder.includes(req.currentUser.authenticationUid)
|
!uploadFolder.includes(req.currentUser.authenticationUid)
|
||||||
) {
|
) {
|
||||||
res.sendStatus(403);
|
res.sendStatus(403);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uploadFolder = normalizeFolder(uploadFolder);
|
||||||
|
|
||||||
|
if (!uploadFolder) {
|
||||||
|
res.status(400).send({ message: 'Invalid upload path.' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const form = new formidable.IncomingForm();
|
const form = new formidable.IncomingForm();
|
||||||
form.uploadDir = config.uploadDir;
|
form.uploadDir = config.uploadDir;
|
||||||
|
|
||||||
@ -58,44 +232,83 @@ const uploadLocal = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
form.parse(req, function (err, fields, files) {
|
form.parse(req, function (err, fields, files) {
|
||||||
const filename = String(fields.filename);
|
if (err) {
|
||||||
const fileTempUrl = files.file.path;
|
console.error('Upload parse error:', err);
|
||||||
|
res.status(500).send(err);
|
||||||
if (!filename) {
|
|
||||||
fs.unlinkSync(fileTempUrl);
|
|
||||||
res.sendStatus(500);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const privateUrl = path.join(
|
const filename = normalizeFilename(String(getFirstValue(fields.filename) || ''));
|
||||||
form.uploadDir,
|
const uploadedFile = getFirstValue(files.file);
|
||||||
folder,
|
const fileTempUrl = uploadedFile && uploadedFile.path;
|
||||||
filename,
|
|
||||||
|
if (!filename || !fileTempUrl) {
|
||||||
|
if (fileTempUrl && fs.existsSync(fileTempUrl)) {
|
||||||
|
fs.unlinkSync(fileTempUrl);
|
||||||
|
}
|
||||||
|
res.status(400).send({ message: 'Invalid uploaded file.' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const privateUrl = assertSafeLocalPath(
|
||||||
|
path.posix.join(uploadFolder, filename),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!privateUrl) {
|
||||||
|
fs.unlinkSync(fileTempUrl);
|
||||||
|
res.status(400).send({ message: 'Invalid upload path.' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ensureDirectoryExistence(privateUrl);
|
ensureDirectoryExistence(privateUrl);
|
||||||
fs.renameSync(fileTempUrl, privateUrl);
|
fs.renameSync(fileTempUrl, privateUrl);
|
||||||
res.sendStatus(200);
|
res.status(200).send({
|
||||||
|
url: buildPublicDownloadUrl(path.posix.join(uploadFolder, filename)),
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
form.on('error', function (err) {
|
form.on('error', function (err) {
|
||||||
|
console.error('Upload form error:', err);
|
||||||
res.status(500).send(err);
|
res.status(500).send(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const downloadLocal = async (req, res) => {
|
const downloadLocal = async (req, res) => {
|
||||||
const privateUrl = req.query.privateUrl;
|
const privateUrl = normalizePrivateUrl(getFirstValue(req.query.privateUrl));
|
||||||
if (!privateUrl) {
|
if (!privateUrl) {
|
||||||
return res.sendStatus(404);
|
return res.sendStatus(404);
|
||||||
}
|
}
|
||||||
res.download(path.join(config.uploadDir, privateUrl));
|
|
||||||
|
const canDownload = await canDownloadPrivateUrl(
|
||||||
|
privateUrl,
|
||||||
|
getFirstValue(req.query.token),
|
||||||
|
);
|
||||||
|
if (!canDownload) {
|
||||||
|
return res.sendStatus(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
const privatePath = assertSafeLocalPath(privateUrl);
|
||||||
|
if (!privatePath) {
|
||||||
|
return res.sendStatus(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.download(privatePath, (err) => {
|
||||||
|
if (!err) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.error('Download error:', err);
|
||||||
|
if (!res.headersSent) {
|
||||||
|
res.sendStatus(404);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const initGCloud = () => {
|
const initGCloud = () => {
|
||||||
const processFile = require("../middlewares/upload");
|
const processFile = require("../middlewares/upload");
|
||||||
const { Storage } = require("@google-cloud/storage");
|
const { Storage } = require("@google-cloud/storage");
|
||||||
|
|
||||||
const crypto = require('crypto')
|
|
||||||
const hash = config.gcloud.hash
|
const hash = config.gcloud.hash
|
||||||
|
|
||||||
const privateKey = process.env.GC_PRIVATE_KEY.replace(/\\\n/g, "\n");
|
const privateKey = process.env.GC_PRIVATE_KEY.replace(/\\\n/g, "\n");
|
||||||
@ -116,14 +329,20 @@ const uploadGCloud = async (folder, req, res) => {
|
|||||||
try {
|
try {
|
||||||
const {hash, bucket, processFile} = initGCloud();
|
const {hash, bucket, processFile} = initGCloud();
|
||||||
await processFile(req, res);
|
await processFile(req, res);
|
||||||
let buffer = await req.file.buffer;
|
const uploadFolder = normalizeFolder(folder);
|
||||||
let filename = await req.body.filename;
|
|
||||||
|
|
||||||
if (!req.file) {
|
if (!req.file) {
|
||||||
return res.status(400).send({ message: "Please upload a file!" });
|
return res.status(400).send({ message: "Please upload a file!" });
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = `${hash}/${folder}/${filename}`;
|
let buffer = await req.file.buffer;
|
||||||
|
let filename = normalizeFilename(await req.body.filename);
|
||||||
|
|
||||||
|
if (!uploadFolder || !filename) {
|
||||||
|
return res.status(400).send({ message: 'Invalid upload path.' });
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = `${hash}/${uploadFolder}/${filename}`;
|
||||||
let blob = bucket.file(path);
|
let blob = bucket.file(path);
|
||||||
|
|
||||||
console.log(path);
|
console.log(path);
|
||||||
@ -140,10 +359,9 @@ const uploadGCloud = async (folder, req, res) => {
|
|||||||
|
|
||||||
console.log(`https://storage.googleapis.com/${bucket.name}/${blob.name}`);
|
console.log(`https://storage.googleapis.com/${bucket.name}/${blob.name}`);
|
||||||
|
|
||||||
blobStream.on("finish", async (data) => {
|
blobStream.on("finish", async () => {
|
||||||
const publicUrl = format(
|
const privateUrl = path.posix.join(uploadFolder, filename);
|
||||||
`https://storage.googleapis.com/${bucket.name}/${blob.name}`
|
const publicUrl = buildPublicDownloadUrl(privateUrl);
|
||||||
);
|
|
||||||
|
|
||||||
res.status(200).send({
|
res.status(200).send({
|
||||||
message: "Uploaded the file successfully: " + path,
|
message: "Uploaded the file successfully: " + path,
|
||||||
@ -163,9 +381,21 @@ const uploadGCloud = async (folder, req, res) => {
|
|||||||
|
|
||||||
const downloadGCloud = async (req, res) => {
|
const downloadGCloud = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const {hash, bucket, processFile} = initGCloud();
|
const {hash, bucket} = initGCloud();
|
||||||
|
|
||||||
|
const privateUrl = normalizePrivateUrl(getFirstValue(await req.query.privateUrl));
|
||||||
|
if (!privateUrl) {
|
||||||
|
return res.sendStatus(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
const canDownload = await canDownloadPrivateUrl(
|
||||||
|
privateUrl,
|
||||||
|
getFirstValue(req.query.token),
|
||||||
|
);
|
||||||
|
if (!canDownload) {
|
||||||
|
return res.sendStatus(404);
|
||||||
|
}
|
||||||
|
|
||||||
const privateUrl = await req.query.privateUrl;
|
|
||||||
const filePath = `${hash}/${privateUrl}`;
|
const filePath = `${hash}/${privateUrl}`;
|
||||||
const file = bucket.file(filePath)
|
const file = bucket.file(filePath)
|
||||||
const fileExists = await file.exists();
|
const fileExists = await file.exists();
|
||||||
@ -176,7 +406,7 @@ const downloadGCloud = async (req, res) => {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
res.status(404).send({
|
res.status(404).send({
|
||||||
message: "Could not download the file. " + err,
|
message: "Could not download the file.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -188,8 +418,13 @@ const downloadGCloud = async (req, res) => {
|
|||||||
|
|
||||||
const deleteGCloud = async (privateUrl) => {
|
const deleteGCloud = async (privateUrl) => {
|
||||||
try {
|
try {
|
||||||
const {hash, bucket, processFile} = initGCloud();
|
const normalizedPrivateUrl = normalizePrivateUrl(privateUrl);
|
||||||
const filePath = `${hash}/${privateUrl}`;
|
if (!normalizedPrivateUrl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {hash, bucket} = initGCloud();
|
||||||
|
const filePath = `${hash}/${normalizedPrivateUrl}`;
|
||||||
|
|
||||||
const file = bucket.file(filePath)
|
const file = bucket.file(filePath)
|
||||||
const fileExists = await file.exists();
|
const fileExists = await file.exists();
|
||||||
@ -208,6 +443,13 @@ module.exports = {
|
|||||||
downloadLocal,
|
downloadLocal,
|
||||||
deleteGCloud,
|
deleteGCloud,
|
||||||
uploadGCloud,
|
uploadGCloud,
|
||||||
downloadGCloud
|
downloadGCloud,
|
||||||
|
normalizePrivateUrl,
|
||||||
|
normalizeFilename,
|
||||||
|
normalizeFolder,
|
||||||
|
buildPublicDownloadUrl,
|
||||||
|
validateFileMetadata,
|
||||||
|
createDownloadToken,
|
||||||
|
isValidDownloadToken,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,7 @@
|
|||||||
const db = require('../db/models');
|
const db = require('../db/models');
|
||||||
const GradesDBApi = require('../db/api/grades');
|
const GradesDBApi = require('../db/api/grades');
|
||||||
const processFile = require("../middlewares/upload");
|
const parseImportFile = require('./importFileParser');
|
||||||
const ValidationError = require('./notifications/errors/validation');
|
const ValidationError = require('./notifications/errors/validation');
|
||||||
const csv = require('csv-parser');
|
|
||||||
const axios = require('axios');
|
|
||||||
const config = require('../config');
|
|
||||||
const stream = require('stream');
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -28,28 +24,13 @@ module.exports = class GradesService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async bulkImport(req, res, sendInvitationEmails = true, host) {
|
static async bulkImport(req, res) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await processFile(req, res);
|
const results = await parseImportFile(req, res);
|
||||||
const bufferStream = new stream.PassThrough();
|
|
||||||
const results = [];
|
|
||||||
|
|
||||||
await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream
|
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
bufferStream
|
|
||||||
.pipe(csv())
|
|
||||||
.on('data', (data) => results.push(data))
|
|
||||||
.on('end', async () => {
|
|
||||||
console.log('CSV results', results);
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.on('error', (error) => reject(error));
|
|
||||||
})
|
|
||||||
|
|
||||||
await GradesDBApi.bulkImport(results, {
|
await GradesDBApi.bulkImport(results, {
|
||||||
transaction,
|
transaction,
|
||||||
@ -70,7 +51,7 @@ module.exports = class GradesService {
|
|||||||
try {
|
try {
|
||||||
let grades = await GradesDBApi.findBy(
|
let grades = await GradesDBApi.findBy(
|
||||||
{id},
|
{id},
|
||||||
{transaction},
|
{ transaction, currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!grades) {
|
if (!grades) {
|
||||||
@ -95,7 +76,7 @@ module.exports = class GradesService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async deleteByIds(ids, currentUser) {
|
static async deleteByIds(ids, currentUser) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|||||||
@ -1,11 +1,7 @@
|
|||||||
const db = require('../db/models');
|
const db = require('../db/models');
|
||||||
const GuardiansDBApi = require('../db/api/guardians');
|
const GuardiansDBApi = require('../db/api/guardians');
|
||||||
const processFile = require("../middlewares/upload");
|
const parseImportFile = require('./importFileParser');
|
||||||
const ValidationError = require('./notifications/errors/validation');
|
const ValidationError = require('./notifications/errors/validation');
|
||||||
const csv = require('csv-parser');
|
|
||||||
const axios = require('axios');
|
|
||||||
const config = require('../config');
|
|
||||||
const stream = require('stream');
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -28,28 +24,13 @@ module.exports = class GuardiansService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async bulkImport(req, res, sendInvitationEmails = true, host) {
|
static async bulkImport(req, res) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await processFile(req, res);
|
const results = await parseImportFile(req, res);
|
||||||
const bufferStream = new stream.PassThrough();
|
|
||||||
const results = [];
|
|
||||||
|
|
||||||
await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream
|
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
bufferStream
|
|
||||||
.pipe(csv())
|
|
||||||
.on('data', (data) => results.push(data))
|
|
||||||
.on('end', async () => {
|
|
||||||
console.log('CSV results', results);
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.on('error', (error) => reject(error));
|
|
||||||
})
|
|
||||||
|
|
||||||
await GuardiansDBApi.bulkImport(results, {
|
await GuardiansDBApi.bulkImport(results, {
|
||||||
transaction,
|
transaction,
|
||||||
@ -70,7 +51,7 @@ module.exports = class GuardiansService {
|
|||||||
try {
|
try {
|
||||||
let guardians = await GuardiansDBApi.findBy(
|
let guardians = await GuardiansDBApi.findBy(
|
||||||
{id},
|
{id},
|
||||||
{transaction},
|
{ transaction, currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!guardians) {
|
if (!guardians) {
|
||||||
@ -95,7 +76,7 @@ module.exports = class GuardiansService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async deleteByIds(ids, currentUser) {
|
static async deleteByIds(ids, currentUser) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|||||||
380
backend/src/services/importFileParser.js
Normal file
380
backend/src/services/importFileParser.js
Normal file
@ -0,0 +1,380 @@
|
|||||||
|
const csv = require('csv-parser');
|
||||||
|
const stream = require('stream');
|
||||||
|
const zlib = require('zlib');
|
||||||
|
const processFile = require('../middlewares/upload');
|
||||||
|
|
||||||
|
function createBadRequest(message) {
|
||||||
|
const error = new Error(message);
|
||||||
|
error.code = 400;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getExtension(filename) {
|
||||||
|
if (!filename) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const match = String(filename).match(/\.([^.]+)$/);
|
||||||
|
return match ? match[1].toLowerCase() : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
async function parseCsvBuffer(buffer) {
|
||||||
|
const bufferStream = new stream.PassThrough();
|
||||||
|
const results = [];
|
||||||
|
|
||||||
|
bufferStream.end(Buffer.from(buffer, 'utf-8'));
|
||||||
|
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
bufferStream
|
||||||
|
.pipe(csv())
|
||||||
|
.on('data', (data) => results.push(data))
|
||||||
|
.on('end', resolve)
|
||||||
|
.on('error', reject);
|
||||||
|
});
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
function findEndOfCentralDirectory(buffer) {
|
||||||
|
const signature = 0x06054b50;
|
||||||
|
const minOffset = Math.max(0, buffer.length - 0xffff - 22);
|
||||||
|
|
||||||
|
for (let offset = buffer.length - 22; offset >= minOffset; offset -= 1) {
|
||||||
|
if (buffer.readUInt32LE(offset) === signature) {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw createBadRequest('Invalid XLSX file.');
|
||||||
|
}
|
||||||
|
|
||||||
|
function readZipEntries(buffer) {
|
||||||
|
const centralDirectorySignature = 0x02014b50;
|
||||||
|
const localFileSignature = 0x04034b50;
|
||||||
|
const endOffset = findEndOfCentralDirectory(buffer);
|
||||||
|
const entriesCount = buffer.readUInt16LE(endOffset + 10);
|
||||||
|
let offset = buffer.readUInt32LE(endOffset + 16);
|
||||||
|
const entries = {};
|
||||||
|
|
||||||
|
for (let index = 0; index < entriesCount; index += 1) {
|
||||||
|
if (buffer.readUInt32LE(offset) !== centralDirectorySignature) {
|
||||||
|
throw createBadRequest('Invalid XLSX file.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const compressionMethod = buffer.readUInt16LE(offset + 10);
|
||||||
|
const compressedSize = buffer.readUInt32LE(offset + 20);
|
||||||
|
const fileNameLength = buffer.readUInt16LE(offset + 28);
|
||||||
|
const extraFieldLength = buffer.readUInt16LE(offset + 30);
|
||||||
|
const fileCommentLength = buffer.readUInt16LE(offset + 32);
|
||||||
|
const localHeaderOffset = buffer.readUInt32LE(offset + 42);
|
||||||
|
const fileName = buffer.toString('utf8', offset + 46, offset + 46 + fileNameLength);
|
||||||
|
|
||||||
|
if (buffer.readUInt32LE(localHeaderOffset) !== localFileSignature) {
|
||||||
|
throw createBadRequest('Invalid XLSX file.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const localFileNameLength = buffer.readUInt16LE(localHeaderOffset + 26);
|
||||||
|
const localExtraFieldLength = buffer.readUInt16LE(localHeaderOffset + 28);
|
||||||
|
const dataOffset = localHeaderOffset + 30 + localFileNameLength + localExtraFieldLength;
|
||||||
|
const compressedData = buffer.slice(dataOffset, dataOffset + compressedSize);
|
||||||
|
|
||||||
|
let data;
|
||||||
|
if (compressionMethod === 0) {
|
||||||
|
data = compressedData;
|
||||||
|
} else if (compressionMethod === 8) {
|
||||||
|
data = zlib.inflateRawSync(compressedData);
|
||||||
|
} else {
|
||||||
|
throw createBadRequest('Unsupported XLSX compression method.');
|
||||||
|
}
|
||||||
|
|
||||||
|
entries[fileName] = data;
|
||||||
|
offset += 46 + fileNameLength + extraFieldLength + fileCommentLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
function xmlText(entries, filename) {
|
||||||
|
return entries[filename] ? entries[filename].toString('utf8') : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeXml(value) {
|
||||||
|
if (value === undefined || value === null) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return String(value)
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/"/g, '"')
|
||||||
|
.replace(/'/g, "'")
|
||||||
|
.replace(/&/g, '&');
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAttribute(source, name) {
|
||||||
|
const escapedName = name.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
|
||||||
|
const match = source.match(new RegExp(`(?:^|\\s)${escapedName}=(['"])(.*?)\\1`));
|
||||||
|
return match ? decodeXml(match[2]) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractTextFromXmlFragment(fragment) {
|
||||||
|
const parts = [];
|
||||||
|
const textRegex = /<t\b[^>]*>([\s\S]*?)<\/t>/g;
|
||||||
|
let textMatch;
|
||||||
|
|
||||||
|
while ((textMatch = textRegex.exec(fragment)) !== null) {
|
||||||
|
parts.push(decodeXml(textMatch[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parts.length) {
|
||||||
|
return parts.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
return decodeXml(fragment.replace(/<[^>]+>/g, ''));
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseSharedStrings(sharedStringsXml) {
|
||||||
|
const sharedStrings = [];
|
||||||
|
const itemRegex = /<si\b[^>]*>([\s\S]*?)<\/si>/g;
|
||||||
|
let itemMatch;
|
||||||
|
|
||||||
|
while ((itemMatch = itemRegex.exec(sharedStringsXml)) !== null) {
|
||||||
|
sharedStrings.push(extractTextFromXmlFragment(itemMatch[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sharedStrings;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseDateStyleIndexes(stylesXml) {
|
||||||
|
if (!stylesXml) {
|
||||||
|
return new Set();
|
||||||
|
}
|
||||||
|
|
||||||
|
const builtInDateFormats = new Set([
|
||||||
|
14, 15, 16, 17, 18, 19, 20, 21, 22,
|
||||||
|
27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
|
||||||
|
45, 46, 47, 50, 51, 52, 53, 54, 55, 56, 57, 58,
|
||||||
|
]);
|
||||||
|
const customDateFormats = new Set();
|
||||||
|
const numberFormatRegex = /<numFmt\b([^>]*)\/>/g;
|
||||||
|
let numberFormatMatch;
|
||||||
|
|
||||||
|
while ((numberFormatMatch = numberFormatRegex.exec(stylesXml)) !== null) {
|
||||||
|
const numberFormatId = Number(getAttribute(numberFormatMatch[1], 'numFmtId'));
|
||||||
|
const formatCode = getAttribute(numberFormatMatch[1], 'formatCode') || '';
|
||||||
|
|
||||||
|
if (Number.isFinite(numberFormatId) && /[dy]/i.test(formatCode)) {
|
||||||
|
customDateFormats.add(numberFormatId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const cellFormatsMatch = stylesXml.match(/<cellXfs\b[^>]*>([\s\S]*?)<\/cellXfs>/);
|
||||||
|
if (!cellFormatsMatch) {
|
||||||
|
return new Set();
|
||||||
|
}
|
||||||
|
|
||||||
|
const styleIndexes = new Set();
|
||||||
|
const formatRegex = /<xf\b([^>]*)\/?>(?:<\/xf>)?/g;
|
||||||
|
let styleIndex = 0;
|
||||||
|
let formatMatch;
|
||||||
|
|
||||||
|
while ((formatMatch = formatRegex.exec(cellFormatsMatch[1])) !== null) {
|
||||||
|
const numberFormatId = Number(getAttribute(formatMatch[1], 'numFmtId'));
|
||||||
|
|
||||||
|
if (builtInDateFormats.has(numberFormatId) || customDateFormats.has(numberFormatId)) {
|
||||||
|
styleIndexes.add(styleIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
styleIndex += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return styleIndexes;
|
||||||
|
}
|
||||||
|
|
||||||
|
function excelSerialDateToIsoDate(value) {
|
||||||
|
const serial = Number(value);
|
||||||
|
|
||||||
|
if (!Number.isFinite(serial)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const milliseconds = Math.round((serial - 25569) * 86400 * 1000);
|
||||||
|
const date = new Date(milliseconds);
|
||||||
|
|
||||||
|
if (Number.isNaN(date.getTime())) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return date.toISOString().slice(0, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
function columnNameToIndex(columnName) {
|
||||||
|
return columnName
|
||||||
|
.toUpperCase()
|
||||||
|
.split('')
|
||||||
|
.reduce((result, char) => result * 26 + char.charCodeAt(0) - 64, 0) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFirstSheetPath(entries) {
|
||||||
|
const workbookXml = xmlText(entries, 'xl/workbook.xml');
|
||||||
|
const relationshipsXml = xmlText(entries, 'xl/_rels/workbook.xml.rels');
|
||||||
|
|
||||||
|
if (!workbookXml || !relationshipsXml) {
|
||||||
|
return entries['xl/worksheets/sheet1.xml'] ? 'xl/worksheets/sheet1.xml' : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sheetMatch = workbookXml.match(/<sheet\b([^>]*)\/?>/);
|
||||||
|
const relationshipId = sheetMatch ? getAttribute(sheetMatch[1], 'r:id') : null;
|
||||||
|
|
||||||
|
if (!relationshipId) {
|
||||||
|
return entries['xl/worksheets/sheet1.xml'] ? 'xl/worksheets/sheet1.xml' : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const relationshipRegex = /<Relationship\b([^>]*)\/?>/g;
|
||||||
|
let relationshipMatch;
|
||||||
|
|
||||||
|
while ((relationshipMatch = relationshipRegex.exec(relationshipsXml)) !== null) {
|
||||||
|
if (getAttribute(relationshipMatch[1], 'Id') === relationshipId) {
|
||||||
|
const target = getAttribute(relationshipMatch[1], 'Target');
|
||||||
|
|
||||||
|
if (!target) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target.startsWith('/')) {
|
||||||
|
return target.replace(/^\//, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
return `xl/${target}`.replace(/\/\.\//g, '/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return entries['xl/worksheets/sheet1.xml'] ? 'xl/worksheets/sheet1.xml' : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readCellValue(cellAttributes, cellBody, sharedStrings, dateStyleIndexes) {
|
||||||
|
const cellType = getAttribute(cellAttributes, 't');
|
||||||
|
const styleIndex = Number(getAttribute(cellAttributes, 's'));
|
||||||
|
|
||||||
|
if (cellType === 'inlineStr') {
|
||||||
|
return extractTextFromXmlFragment(cellBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
const valueMatch = cellBody.match(/<v\b[^>]*>([\s\S]*?)<\/v>/);
|
||||||
|
const rawValue = valueMatch ? decodeXml(valueMatch[1]) : '';
|
||||||
|
|
||||||
|
if (cellType === 's') {
|
||||||
|
return sharedStrings[Number(rawValue)] || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cellType === 'b') {
|
||||||
|
return rawValue === '1' ? 'true' : 'false';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dateStyleIndexes.has(styleIndex) && rawValue !== '') {
|
||||||
|
return excelSerialDateToIsoDate(rawValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rawValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseWorksheetRows(sheetXml, sharedStrings, dateStyleIndexes) {
|
||||||
|
const rows = [];
|
||||||
|
const rowRegex = /<row\b[^>]*>([\s\S]*?)<\/row>/g;
|
||||||
|
let rowMatch;
|
||||||
|
|
||||||
|
while ((rowMatch = rowRegex.exec(sheetXml)) !== null) {
|
||||||
|
const row = [];
|
||||||
|
const cellRegex = /<c\b([^>]*?)>([\s\S]*?)<\/c>|<c\b([^>]*?)\/>/g;
|
||||||
|
let cellMatch;
|
||||||
|
let nextColumnIndex = 0;
|
||||||
|
|
||||||
|
while ((cellMatch = cellRegex.exec(rowMatch[1])) !== null) {
|
||||||
|
const cellAttributes = cellMatch[1] || cellMatch[3] || '';
|
||||||
|
const cellBody = cellMatch[2] || '';
|
||||||
|
const cellReference = getAttribute(cellAttributes, 'r');
|
||||||
|
const columnMatch = cellReference ? cellReference.match(/[A-Z]+/i) : null;
|
||||||
|
const columnIndex = columnMatch ? columnNameToIndex(columnMatch[0]) : nextColumnIndex;
|
||||||
|
|
||||||
|
row[columnIndex] = readCellValue(cellAttributes, cellBody, sharedStrings, dateStyleIndexes);
|
||||||
|
nextColumnIndex = columnIndex + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (row.some((value) => value !== undefined && value !== '')) {
|
||||||
|
rows.push(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
function rowsToObjects(rows) {
|
||||||
|
if (!rows.length) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const headers = rows[0].map((header) => String(header || '').replace(/^\uFEFF/, '').trim());
|
||||||
|
|
||||||
|
return rows.slice(1).reduce((items, row) => {
|
||||||
|
const item = {};
|
||||||
|
|
||||||
|
headers.forEach((header, index) => {
|
||||||
|
if (!header) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = row[index];
|
||||||
|
item[header] = value === undefined ? '' : value;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (Object.values(item).some((value) => value !== '')) {
|
||||||
|
items.push(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseXlsxBuffer(buffer) {
|
||||||
|
const entries = readZipEntries(buffer);
|
||||||
|
const sheetPath = getFirstSheetPath(entries);
|
||||||
|
|
||||||
|
if (!sheetPath || !entries[sheetPath]) {
|
||||||
|
throw createBadRequest('XLSX file does not contain a worksheet.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const sharedStrings = parseSharedStrings(xmlText(entries, 'xl/sharedStrings.xml'));
|
||||||
|
const dateStyleIndexes = parseDateStyleIndexes(xmlText(entries, 'xl/styles.xml'));
|
||||||
|
const rows = parseWorksheetRows(xmlText(entries, sheetPath), sharedStrings, dateStyleIndexes);
|
||||||
|
|
||||||
|
return rowsToObjects(rows);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function parseImportFile(req, res) {
|
||||||
|
await processFile(req, res);
|
||||||
|
|
||||||
|
if (!req.file || !req.file.buffer) {
|
||||||
|
throw createBadRequest('No import file was uploaded.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const filename = req.file.originalname || req.body.filename || '';
|
||||||
|
const extension = getExtension(filename);
|
||||||
|
|
||||||
|
if (extension === 'csv') {
|
||||||
|
return parseCsvBuffer(req.file.buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extension === 'xlsx') {
|
||||||
|
return parseXlsxBuffer(req.file.buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extension === 'xls') {
|
||||||
|
throw createBadRequest('Legacy .xls imports are not supported yet. Please save the spreadsheet as .xlsx or .csv.');
|
||||||
|
}
|
||||||
|
|
||||||
|
throw createBadRequest('Invalid import format. Allowed formats: .csv, .xlsx.');
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = parseImportFile;
|
||||||
|
module.exports.parseCsvBuffer = parseCsvBuffer;
|
||||||
|
module.exports.parseXlsxBuffer = parseXlsxBuffer;
|
||||||
@ -1,11 +1,7 @@
|
|||||||
const db = require('../db/models');
|
const db = require('../db/models');
|
||||||
const InvoicesDBApi = require('../db/api/invoices');
|
const InvoicesDBApi = require('../db/api/invoices');
|
||||||
const processFile = require("../middlewares/upload");
|
const parseImportFile = require('./importFileParser');
|
||||||
const ValidationError = require('./notifications/errors/validation');
|
const ValidationError = require('./notifications/errors/validation');
|
||||||
const csv = require('csv-parser');
|
|
||||||
const axios = require('axios');
|
|
||||||
const config = require('../config');
|
|
||||||
const stream = require('stream');
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -28,28 +24,13 @@ module.exports = class InvoicesService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async bulkImport(req, res, sendInvitationEmails = true, host) {
|
static async bulkImport(req, res) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await processFile(req, res);
|
const results = await parseImportFile(req, res);
|
||||||
const bufferStream = new stream.PassThrough();
|
|
||||||
const results = [];
|
|
||||||
|
|
||||||
await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream
|
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
bufferStream
|
|
||||||
.pipe(csv())
|
|
||||||
.on('data', (data) => results.push(data))
|
|
||||||
.on('end', async () => {
|
|
||||||
console.log('CSV results', results);
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.on('error', (error) => reject(error));
|
|
||||||
})
|
|
||||||
|
|
||||||
await InvoicesDBApi.bulkImport(results, {
|
await InvoicesDBApi.bulkImport(results, {
|
||||||
transaction,
|
transaction,
|
||||||
@ -70,7 +51,7 @@ module.exports = class InvoicesService {
|
|||||||
try {
|
try {
|
||||||
let invoices = await InvoicesDBApi.findBy(
|
let invoices = await InvoicesDBApi.findBy(
|
||||||
{id},
|
{id},
|
||||||
{transaction},
|
{ transaction, currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!invoices) {
|
if (!invoices) {
|
||||||
@ -95,7 +76,7 @@ module.exports = class InvoicesService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async deleteByIds(ids, currentUser) {
|
static async deleteByIds(ids, currentUser) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|||||||
@ -2,20 +2,10 @@ const axios = require('axios');
|
|||||||
const config = require('../config');
|
const config = require('../config');
|
||||||
const { LocalAIApi } = require('../ai/LocalAIApi');
|
const { LocalAIApi } = require('../ai/LocalAIApi');
|
||||||
|
|
||||||
const loadRoleService = () => {
|
|
||||||
try {
|
|
||||||
return require('./roles');
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Role service is missing. Advanced roles are required for this operation.', error);
|
|
||||||
const err = new Error('Role service is missing. Advanced roles are required for this operation.');
|
|
||||||
err.originalError = error;
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = class OpenAiService {
|
module.exports = class OpenAiService {
|
||||||
static async getWidget(payload, userId, roleId) {
|
static async getWidget(payload) {
|
||||||
const RoleService = loadRoleService();
|
|
||||||
const response = await axios.post(
|
const response = await axios.post(
|
||||||
`${config.flHost}/${config.project_uuid}/project_customization_widgets.json`,
|
`${config.flHost}/${config.project_uuid}/project_customization_widgets.json`,
|
||||||
payload,
|
payload,
|
||||||
@ -23,7 +13,6 @@ module.exports = class OpenAiService {
|
|||||||
|
|
||||||
if (response.status >= 200 && response.status < 300) {
|
if (response.status >= 200 && response.status < 300) {
|
||||||
const { widget_id } = await response.data;
|
const { widget_id } = await response.data;
|
||||||
await RoleService.addRoleInfo(roleId, userId, 'widgets', widget_id);
|
|
||||||
return widget_id;
|
return widget_id;
|
||||||
} else {
|
} else {
|
||||||
console.error('=======error=======', response.data);
|
console.error('=======error=======', response.data);
|
||||||
|
|||||||
@ -1,11 +1,7 @@
|
|||||||
const db = require('../db/models');
|
const db = require('../db/models');
|
||||||
const PaymentsDBApi = require('../db/api/payments');
|
const PaymentsDBApi = require('../db/api/payments');
|
||||||
const processFile = require("../middlewares/upload");
|
const parseImportFile = require('./importFileParser');
|
||||||
const ValidationError = require('./notifications/errors/validation');
|
const ValidationError = require('./notifications/errors/validation');
|
||||||
const csv = require('csv-parser');
|
|
||||||
const axios = require('axios');
|
|
||||||
const config = require('../config');
|
|
||||||
const stream = require('stream');
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -28,28 +24,13 @@ module.exports = class PaymentsService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async bulkImport(req, res, sendInvitationEmails = true, host) {
|
static async bulkImport(req, res) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await processFile(req, res);
|
const results = await parseImportFile(req, res);
|
||||||
const bufferStream = new stream.PassThrough();
|
|
||||||
const results = [];
|
|
||||||
|
|
||||||
await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream
|
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
bufferStream
|
|
||||||
.pipe(csv())
|
|
||||||
.on('data', (data) => results.push(data))
|
|
||||||
.on('end', async () => {
|
|
||||||
console.log('CSV results', results);
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.on('error', (error) => reject(error));
|
|
||||||
})
|
|
||||||
|
|
||||||
await PaymentsDBApi.bulkImport(results, {
|
await PaymentsDBApi.bulkImport(results, {
|
||||||
transaction,
|
transaction,
|
||||||
@ -70,7 +51,7 @@ module.exports = class PaymentsService {
|
|||||||
try {
|
try {
|
||||||
let payments = await PaymentsDBApi.findBy(
|
let payments = await PaymentsDBApi.findBy(
|
||||||
{id},
|
{id},
|
||||||
{transaction},
|
{ transaction, currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!payments) {
|
if (!payments) {
|
||||||
@ -95,7 +76,7 @@ module.exports = class PaymentsService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async deleteByIds(ids, currentUser) {
|
static async deleteByIds(ids, currentUser) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|||||||
@ -1,11 +1,7 @@
|
|||||||
const db = require('../db/models');
|
const db = require('../db/models');
|
||||||
const PermissionsDBApi = require('../db/api/permissions');
|
const PermissionsDBApi = require('../db/api/permissions');
|
||||||
const processFile = require("../middlewares/upload");
|
const parseImportFile = require('./importFileParser');
|
||||||
const ValidationError = require('./notifications/errors/validation');
|
const ValidationError = require('./notifications/errors/validation');
|
||||||
const csv = require('csv-parser');
|
|
||||||
const axios = require('axios');
|
|
||||||
const config = require('../config');
|
|
||||||
const stream = require('stream');
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -28,28 +24,13 @@ module.exports = class PermissionsService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async bulkImport(req, res, sendInvitationEmails = true, host) {
|
static async bulkImport(req, res) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await processFile(req, res);
|
const results = await parseImportFile(req, res);
|
||||||
const bufferStream = new stream.PassThrough();
|
|
||||||
const results = [];
|
|
||||||
|
|
||||||
await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream
|
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
bufferStream
|
|
||||||
.pipe(csv())
|
|
||||||
.on('data', (data) => results.push(data))
|
|
||||||
.on('end', async () => {
|
|
||||||
console.log('CSV results', results);
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.on('error', (error) => reject(error));
|
|
||||||
})
|
|
||||||
|
|
||||||
await PermissionsDBApi.bulkImport(results, {
|
await PermissionsDBApi.bulkImport(results, {
|
||||||
transaction,
|
transaction,
|
||||||
@ -95,7 +76,7 @@ module.exports = class PermissionsService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async deleteByIds(ids, currentUser) {
|
static async deleteByIds(ids, currentUser) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|||||||
@ -1,11 +1,7 @@
|
|||||||
const db = require('../db/models');
|
const db = require('../db/models');
|
||||||
const ProductsDBApi = require('../db/api/products');
|
const ProductsDBApi = require('../db/api/products');
|
||||||
const processFile = require("../middlewares/upload");
|
const parseImportFile = require('./importFileParser');
|
||||||
const ValidationError = require('./notifications/errors/validation');
|
const ValidationError = require('./notifications/errors/validation');
|
||||||
const csv = require('csv-parser');
|
|
||||||
const axios = require('axios');
|
|
||||||
const config = require('../config');
|
|
||||||
const stream = require('stream');
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -28,28 +24,13 @@ module.exports = class ProductsService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async bulkImport(req, res, sendInvitationEmails = true, host) {
|
static async bulkImport(req, res) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await processFile(req, res);
|
const results = await parseImportFile(req, res);
|
||||||
const bufferStream = new stream.PassThrough();
|
|
||||||
const results = [];
|
|
||||||
|
|
||||||
await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream
|
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
bufferStream
|
|
||||||
.pipe(csv())
|
|
||||||
.on('data', (data) => results.push(data))
|
|
||||||
.on('end', async () => {
|
|
||||||
console.log('CSV results', results);
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.on('error', (error) => reject(error));
|
|
||||||
})
|
|
||||||
|
|
||||||
await ProductsDBApi.bulkImport(results, {
|
await ProductsDBApi.bulkImport(results, {
|
||||||
transaction,
|
transaction,
|
||||||
@ -70,7 +51,7 @@ module.exports = class ProductsService {
|
|||||||
try {
|
try {
|
||||||
let products = await ProductsDBApi.findBy(
|
let products = await ProductsDBApi.findBy(
|
||||||
{id},
|
{id},
|
||||||
{transaction},
|
{ transaction, currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!products) {
|
if (!products) {
|
||||||
@ -95,7 +76,7 @@ module.exports = class ProductsService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async deleteByIds(ids, currentUser) {
|
static async deleteByIds(ids, currentUser) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|||||||
@ -1,19 +1,41 @@
|
|||||||
const db = require('../db/models');
|
const db = require('../db/models');
|
||||||
const RolesDBApi = require('../db/api/roles');
|
const RolesDBApi = require('../db/api/roles');
|
||||||
const processFile = require("../middlewares/upload");
|
const parseImportFile = require('./importFileParser');
|
||||||
const ValidationError = require('./notifications/errors/validation');
|
const ValidationError = require('./notifications/errors/validation');
|
||||||
const csv = require('csv-parser');
|
|
||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
const config = require('../config');
|
const config = require('../config');
|
||||||
const stream = require('stream');
|
const { getCurrentUserSchoolId } = require('../db/api/schoolScope');
|
||||||
|
const { executeReadOnlySelect } = require('./sqlSafety');
|
||||||
|
|
||||||
|
const WIDGET_CUSTOMIZATION_KEY = 'widgets';
|
||||||
|
const UUID_REGEX = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
||||||
|
|
||||||
|
function badRequest(message) {
|
||||||
|
const error = new Error(message);
|
||||||
|
error.code = 400;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertWidgetKey(key) {
|
||||||
|
if (key !== WIDGET_CUSTOMIZATION_KEY) {
|
||||||
|
throw badRequest('Invalid role customization key.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertUuid(value, label) {
|
||||||
|
if (typeof value !== 'string' || !UUID_REGEX.test(value)) {
|
||||||
|
throw badRequest(`${label} must be a valid UUID.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function buildWidgetResult(widget, queryResult, queryString) {
|
|
||||||
if (queryResult[0] && queryResult[0].length) {
|
function buildWidgetResult(widget, rows, queryString) {
|
||||||
const key = Object.keys(queryResult[0][0])[0];
|
if (Array.isArray(rows) && rows.length) {
|
||||||
const value = widget.widget_type === 'scalar' ? queryResult[0][0][key] : queryResult[0];
|
const key = Object.keys(rows[0])[0];
|
||||||
|
const value = widget.widget_type === 'scalar' ? rows[0][key] : rows;
|
||||||
const widgetData = JSON.parse(widget.data);
|
const widgetData = JSON.parse(widget.data);
|
||||||
return { ...widget, ...widgetData, value, query: queryString };
|
return { ...widget, ...widgetData, value, query: queryString };
|
||||||
} else {
|
} else {
|
||||||
@ -21,14 +43,16 @@ function buildWidgetResult(widget, queryResult, queryString) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function executeQuery(queryString, currentUser) {
|
async function executeQuery(queryString, replacements) {
|
||||||
try {
|
try {
|
||||||
return await db.sequelize.query(queryString, {
|
return await executeReadOnlySelect(queryString, {
|
||||||
replacements: { organizationId: currentUser.organizationId },
|
replacements,
|
||||||
|
maxRows: 1000,
|
||||||
|
timeoutMs: 5000,
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.error('Widget SQL execution failed:', e);
|
||||||
return [];
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,19 +73,36 @@ function insertWhereConditions(queryString, whereConditions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function constructWhereConditions(mainTable, currentUser, replacements) {
|
function constructWhereConditions(mainTable, currentUser, replacements) {
|
||||||
const { organizationId, app_role: { globalAccess } } = currentUser;
|
const globalAccess = currentUser?.app_role?.globalAccess;
|
||||||
const tablesWithoutOrgId = ['permissions', 'roles'];
|
const tablesWithoutSchoolScope = ['permissions', 'roles'];
|
||||||
let whereConditions = '';
|
const model = db[mainTable];
|
||||||
|
const rawAttributes = model?.rawAttributes || {};
|
||||||
|
const conditions = [];
|
||||||
|
|
||||||
if (!globalAccess && !tablesWithoutOrgId.includes(mainTable)) {
|
if (!globalAccess && !tablesWithoutSchoolScope.includes(mainTable)) {
|
||||||
whereConditions += `"${mainTable}"."organizationId" = :organizationId`;
|
const schoolId = getCurrentUserSchoolId(currentUser);
|
||||||
replacements.organizationId = organizationId;
|
|
||||||
|
if (!schoolId) {
|
||||||
|
conditions.push('1 = 0');
|
||||||
|
} else if (mainTable === 'schools') {
|
||||||
|
conditions.push(`"${mainTable}"."id" = :schoolId`);
|
||||||
|
replacements.schoolId = schoolId;
|
||||||
|
} else if (rawAttributes.schoolId) {
|
||||||
|
conditions.push(`"${mainTable}"."schoolId" = :schoolId`);
|
||||||
|
replacements.schoolId = schoolId;
|
||||||
|
} else if (rawAttributes.schoolsId) {
|
||||||
|
conditions.push(`"${mainTable}"."schoolsId" = :schoolId`);
|
||||||
|
replacements.schoolId = schoolId;
|
||||||
|
} else {
|
||||||
|
conditions.push('1 = 0');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
whereConditions += whereConditions ? ' AND ' : '';
|
if (rawAttributes.deletedAt) {
|
||||||
whereConditions += `"${mainTable}"."deletedAt" IS NULL`;
|
conditions.push(`"${mainTable}"."deletedAt" IS NULL`);
|
||||||
|
}
|
||||||
|
|
||||||
return whereConditions;
|
return conditions.join(' AND ');
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractTableName(queryString) {
|
function extractTableName(queryString) {
|
||||||
@ -70,23 +111,22 @@ function extractTableName(queryString) {
|
|||||||
return match ? match[2] : null;
|
return match ? match[2] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildQueryString(widget, currentUser) {
|
function buildQuery(widget, currentUser) {
|
||||||
let queryString = widget?.query || '';
|
let queryString = widget?.query || '';
|
||||||
const tableName = extractTableName(queryString);
|
const tableName = extractTableName(queryString);
|
||||||
const mainTable = JSON.parse(widget?.data)?.main_table || tableName;
|
const mainTable = JSON.parse(widget?.data)?.main_table || tableName;
|
||||||
const replacements = {};
|
const replacements = {};
|
||||||
const whereConditions = constructWhereConditions(mainTable, currentUser, replacements);
|
const whereConditions = constructWhereConditions(mainTable, currentUser, replacements);
|
||||||
queryString = insertWhereConditions(queryString, whereConditions);
|
queryString = insertWhereConditions(queryString, whereConditions);
|
||||||
console.log(queryString, 'queryString');
|
return { queryString, replacements };
|
||||||
return queryString;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function constructWidgetsResults(widgets, currentUser) {
|
async function constructWidgetsResults(widgets, currentUser) {
|
||||||
const widgetsResults = [];
|
const widgetsResults = [];
|
||||||
for (const widget of widgets) {
|
for (const widget of widgets) {
|
||||||
if (!widget) continue;
|
if (!widget) continue;
|
||||||
const queryString = buildQueryString(widget, currentUser);
|
const { queryString, replacements } = buildQuery(widget, currentUser);
|
||||||
const queryResult = await executeQuery(queryString, currentUser);
|
const queryResult = await executeQuery(queryString, replacements);
|
||||||
widgetsResults.push(buildWidgetResult(widget, queryResult, queryString));
|
widgetsResults.push(buildWidgetResult(widget, queryResult, queryString));
|
||||||
}
|
}
|
||||||
return widgetsResults;
|
return widgetsResults;
|
||||||
@ -97,6 +137,10 @@ async function fetchWidgetsData(widgets) {
|
|||||||
axios.get(`${config.flHost}/${config.project_uuid}/project_customization_widgets/${widgetId}.json`)
|
axios.get(`${config.flHost}/${config.project_uuid}/project_customization_widgets/${widgetId}.json`)
|
||||||
);
|
);
|
||||||
const widgetResults = widgetPromises ? await Promise.allSettled(widgetPromises) : [];
|
const widgetResults = widgetPromises ? await Promise.allSettled(widgetPromises) : [];
|
||||||
|
widgetResults
|
||||||
|
.filter(result => result.status === 'rejected')
|
||||||
|
.forEach(result => console.error('Widget fetch failed:', result.reason));
|
||||||
|
|
||||||
return widgetResults
|
return widgetResults
|
||||||
.filter(result => result.status === 'fulfilled')
|
.filter(result => result.status === 'fulfilled')
|
||||||
.map(result => result.value.data);
|
.map(result => result.value.data);
|
||||||
@ -116,7 +160,7 @@ function parseCustomization(role) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function findRole(roleId, currentUser) {
|
async function findRole(roleId) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
try {
|
try {
|
||||||
const role = roleId
|
const role = roleId
|
||||||
@ -148,28 +192,13 @@ module.exports = class RolesService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async bulkImport(req, res, sendInvitationEmails = true, host) {
|
static async bulkImport(req, res) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await processFile(req, res);
|
const results = await parseImportFile(req, res);
|
||||||
const bufferStream = new stream.PassThrough();
|
|
||||||
const results = [];
|
|
||||||
|
|
||||||
await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream
|
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
bufferStream
|
|
||||||
.pipe(csv())
|
|
||||||
.on('data', (data) => results.push(data))
|
|
||||||
.on('end', async () => {
|
|
||||||
console.log('CSV results', results);
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.on('error', (error) => reject(error));
|
|
||||||
})
|
|
||||||
|
|
||||||
await RolesDBApi.bulkImport(results, {
|
await RolesDBApi.bulkImport(results, {
|
||||||
transaction,
|
transaction,
|
||||||
@ -215,7 +244,7 @@ module.exports = class RolesService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async deleteByIds(ids, currentUser) {
|
static async deleteByIds(ids, currentUser) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
@ -254,22 +283,22 @@ module.exports = class RolesService {
|
|||||||
|
|
||||||
|
|
||||||
static async addRoleInfo(roleId, userId, key, widgetId, currentUser) {
|
static async addRoleInfo(roleId, userId, key, widgetId, currentUser) {
|
||||||
const regexExpForUuid = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/gi;
|
assertWidgetKey(key);
|
||||||
const widgetIdIsUUID = regexExpForUuid.test(widgetId);
|
assertUuid(widgetId, 'Widget ID');
|
||||||
|
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
let role;
|
|
||||||
if (roleId) {
|
|
||||||
role = await RolesDBApi.findBy({ id: roleId }, { transaction });
|
|
||||||
} else {
|
|
||||||
role = await RolesDBApi.findBy({ name: 'User' }, { transaction });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!role) {
|
|
||||||
throw new ValidationError('rolesNotFound');
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
let role;
|
||||||
|
if (roleId) {
|
||||||
|
role = await RolesDBApi.findBy({ id: roleId }, { transaction });
|
||||||
|
} else {
|
||||||
|
role = await RolesDBApi.findBy({ name: 'User' }, { transaction });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!role) {
|
||||||
|
throw new ValidationError('rolesNotFound');
|
||||||
|
}
|
||||||
|
|
||||||
let customization = {};
|
let customization = {};
|
||||||
try {
|
try {
|
||||||
customization = JSON.parse(role.role_customization || '{}');
|
customization = JSON.parse(role.role_customization || '{}');
|
||||||
@ -277,12 +306,12 @@ module.exports = class RolesService {
|
|||||||
console.log(e);
|
console.log(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (widgetIdIsUUID && Array.isArray(customization[key])) {
|
if (Array.isArray(customization[key])) {
|
||||||
const el = customization[key].find((e) => e === widgetId);
|
const el = customization[key].find((e) => e === widgetId);
|
||||||
!el ? customization[key].unshift(widgetId) : null;
|
if (!el) {
|
||||||
}
|
customization[key].unshift(widgetId);
|
||||||
|
}
|
||||||
if (widgetIdIsUUID && !customization[key]) {
|
} else {
|
||||||
customization[key] = [widgetId];
|
customization[key] = [widgetId];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,33 +339,37 @@ module.exports = class RolesService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static async removeRoleInfoById(infoId, roleId, key, currentUser) {
|
static async removeRoleInfoById(infoId, roleId, key, currentUser) {
|
||||||
|
assertWidgetKey(key);
|
||||||
|
assertUuid(infoId, 'Widget ID');
|
||||||
|
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|
||||||
let role;
|
|
||||||
if (roleId) {
|
|
||||||
role = await RolesDBApi.findBy({ id: roleId }, { transaction });
|
|
||||||
} else {
|
|
||||||
role = await RolesDBApi.findBy({ name: 'User' }, { transaction });
|
|
||||||
}
|
|
||||||
if (!role) {
|
|
||||||
await transaction.rollback();
|
|
||||||
throw new ValidationError('rolesNotFound');
|
|
||||||
}
|
|
||||||
|
|
||||||
let customization = {};
|
|
||||||
try {
|
try {
|
||||||
customization = JSON.parse(role.role_customization || '{}');
|
let role;
|
||||||
} catch (e) {
|
if (roleId) {
|
||||||
console.log(e);
|
role = await RolesDBApi.findBy({ id: roleId }, { transaction });
|
||||||
}
|
} else {
|
||||||
|
role = await RolesDBApi.findBy({ name: 'User' }, { transaction });
|
||||||
|
}
|
||||||
|
if (!role) {
|
||||||
|
throw new ValidationError('rolesNotFound');
|
||||||
|
}
|
||||||
|
|
||||||
customization[key] = customization[key].filter(
|
let customization = {};
|
||||||
(item) => item !== infoId,
|
try {
|
||||||
);
|
customization = JSON.parse(role.role_customization || '{}');
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
|
||||||
const response = await axios.delete(`${config.flHost}/${config.project_uuid}/project_customization_widgets/${infoId}.json`);
|
if (!Array.isArray(customization[key])) {
|
||||||
const { status } = await response;
|
throw badRequest('Widget customization not found.');
|
||||||
try {
|
}
|
||||||
|
|
||||||
|
customization[key] = customization[key].filter(
|
||||||
|
(item) => item !== infoId,
|
||||||
|
);
|
||||||
|
|
||||||
|
await axios.delete(`${config.flHost}/${config.project_uuid}/project_customization_widgets/${infoId}.json`);
|
||||||
const result = await RolesDBApi.update(
|
const result = await RolesDBApi.update(
|
||||||
role.id,
|
role.id,
|
||||||
{
|
{
|
||||||
@ -362,14 +395,8 @@ module.exports = class RolesService {
|
|||||||
static async getRoleInfoByKey(key, roleId, currentUser) {
|
static async getRoleInfoByKey(key, roleId, currentUser) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|
||||||
const organizationId = currentUser.organizationId;
|
|
||||||
let globalAccess = currentUser.app_role?.globalAccess;
|
|
||||||
let queryString = '';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const role = await findRole(roleId, currentUser);
|
const role = await findRole(roleId);
|
||||||
const customization = parseCustomization(role);
|
const customization = parseCustomization(role);
|
||||||
|
|
||||||
let result;
|
let result;
|
||||||
@ -384,13 +411,8 @@ module.exports = class RolesService {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
} finally {
|
throw error;
|
||||||
if (transaction.finished !== 'commit') {
|
|
||||||
await transaction.rollback();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,22 +1,50 @@
|
|||||||
const db = require('../db/models');
|
const db = require('../db/models');
|
||||||
const SchoolsDBApi = require('../db/api/schools');
|
const SchoolsDBApi = require('../db/api/schools');
|
||||||
const processFile = require("../middlewares/upload");
|
const parseImportFile = require('./importFileParser');
|
||||||
const ValidationError = require('./notifications/errors/validation');
|
const ValidationError = require('./notifications/errors/validation');
|
||||||
const csv = require('csv-parser');
|
|
||||||
const axios = require('axios');
|
|
||||||
const config = require('../config');
|
|
||||||
const stream = require('stream');
|
|
||||||
|
|
||||||
|
const SCHOOL_STATUSES = new Set(['active', 'setup', 'suspended']);
|
||||||
|
|
||||||
|
function cleanString(value) {
|
||||||
|
if (value === undefined || value === null) return null;
|
||||||
|
const text = String(value).trim();
|
||||||
|
return text || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeSchoolData(data = {}) {
|
||||||
|
const normalized = {
|
||||||
|
name: cleanString(data.name),
|
||||||
|
nif: cleanString(data.nif),
|
||||||
|
phone: cleanString(data.phone),
|
||||||
|
email: cleanString(data.email),
|
||||||
|
province: cleanString(data.province),
|
||||||
|
municipality: cleanString(data.municipality),
|
||||||
|
address: cleanString(data.address),
|
||||||
|
logoUrl: cleanString(data.logoUrl),
|
||||||
|
status: cleanString(data.status) || 'active',
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!normalized.name) {
|
||||||
|
throw new ValidationError('schoolsNameRequired');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (normalized.email && !normalized.email.includes('@')) {
|
||||||
|
throw new ValidationError('schoolsEmailInvalid');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SCHOOL_STATUSES.has(normalized.status)) {
|
||||||
|
throw new ValidationError('schoolsStatusInvalid');
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = class SchoolsService {
|
module.exports = class SchoolsService {
|
||||||
static async create(data, currentUser) {
|
static async create(data, currentUser) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
try {
|
try {
|
||||||
await SchoolsDBApi.create(
|
await SchoolsDBApi.create(
|
||||||
data,
|
normalizeSchoolData(data),
|
||||||
{
|
{
|
||||||
currentUser,
|
currentUser,
|
||||||
transaction,
|
transaction,
|
||||||
@ -28,28 +56,13 @@ module.exports = class SchoolsService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async bulkImport(req, res, sendInvitationEmails = true, host) {
|
static async bulkImport(req, res) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await processFile(req, res);
|
const results = await parseImportFile(req, res);
|
||||||
const bufferStream = new stream.PassThrough();
|
|
||||||
const results = [];
|
|
||||||
|
|
||||||
await bufferStream.end(Buffer.from(req.file.buffer, "utf-8")); // convert Buffer to Stream
|
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
bufferStream
|
|
||||||
.pipe(csv())
|
|
||||||
.on('data', (data) => results.push(data))
|
|
||||||
.on('end', async () => {
|
|
||||||
console.log('CSV results', results);
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.on('error', (error) => reject(error));
|
|
||||||
})
|
|
||||||
|
|
||||||
await SchoolsDBApi.bulkImport(results, {
|
await SchoolsDBApi.bulkImport(results, {
|
||||||
transaction,
|
transaction,
|
||||||
@ -70,7 +83,7 @@ module.exports = class SchoolsService {
|
|||||||
try {
|
try {
|
||||||
let schools = await SchoolsDBApi.findBy(
|
let schools = await SchoolsDBApi.findBy(
|
||||||
{id},
|
{id},
|
||||||
{transaction},
|
{ transaction, currentUser },
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!schools) {
|
if (!schools) {
|
||||||
@ -81,7 +94,7 @@ module.exports = class SchoolsService {
|
|||||||
|
|
||||||
const updatedSchools = await SchoolsDBApi.update(
|
const updatedSchools = await SchoolsDBApi.update(
|
||||||
id,
|
id,
|
||||||
data,
|
normalizeSchoolData(data),
|
||||||
{
|
{
|
||||||
currentUser,
|
currentUser,
|
||||||
transaction,
|
transaction,
|
||||||
@ -95,7 +108,7 @@ module.exports = class SchoolsService {
|
|||||||
await transaction.rollback();
|
await transaction.rollback();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
static async deleteByIds(ids, currentUser) {
|
static async deleteByIds(ids, currentUser) {
|
||||||
const transaction = await db.sequelize.transaction();
|
const transaction = await db.sequelize.transaction();
|
||||||
|
|||||||
@ -3,6 +3,35 @@ const ValidationError = require('./notifications/errors/validation');
|
|||||||
|
|
||||||
const Sequelize = db.Sequelize;
|
const Sequelize = db.Sequelize;
|
||||||
const Op = Sequelize.Op;
|
const Op = Sequelize.Op;
|
||||||
|
const { getCurrentUserSchoolId } = require('../db/api/schoolScope');
|
||||||
|
|
||||||
|
const MAX_SEARCH_QUERY_LENGTH = 100;
|
||||||
|
const MAX_RESULTS_PER_TABLE = 10;
|
||||||
|
const MAX_TOTAL_SEARCH_RESULTS = 100;
|
||||||
|
|
||||||
|
function normalizeSearchQuery(searchQuery) {
|
||||||
|
if (typeof searchQuery !== 'string') {
|
||||||
|
throw new ValidationError('iam.errors.searchQueryRequired');
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalized = searchQuery.trim();
|
||||||
|
if (!normalized) {
|
||||||
|
throw new ValidationError('iam.errors.searchQueryRequired');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (normalized.length > MAX_SEARCH_QUERY_LENGTH) {
|
||||||
|
const error = new Error(`Search query is too long. Maximum length is ${MAX_SEARCH_QUERY_LENGTH} characters.`);
|
||||||
|
error.code = 400;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeLikePattern(value) {
|
||||||
|
return value.replace(/[\\%_]/g, '\\$&');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} permission
|
* @param {string} permission
|
||||||
@ -14,7 +43,10 @@ async function checkPermissions(permission, currentUser) {
|
|||||||
throw new ValidationError('auth.unauthorized');
|
throw new ValidationError('auth.unauthorized');
|
||||||
}
|
}
|
||||||
|
|
||||||
const userPermission = currentUser.custom_permissions.find(
|
const customPermissions = Array.isArray(currentUser.custom_permissions)
|
||||||
|
? currentUser.custom_permissions
|
||||||
|
: [];
|
||||||
|
const userPermission = customPermissions.find(
|
||||||
(cp) => cp.name === permission,
|
(cp) => cp.name === permission,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -22,25 +54,21 @@ async function checkPermissions(permission, currentUser) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
if (!currentUser.app_role) {
|
||||||
if (!currentUser.app_role) {
|
throw new ValidationError('auth.forbidden');
|
||||||
throw new ValidationError('auth.forbidden');
|
|
||||||
}
|
|
||||||
|
|
||||||
const permissions = await currentUser.app_role.getPermissions();
|
|
||||||
|
|
||||||
return !!permissions.find((p) => p.name === permission);
|
|
||||||
} catch (e) {
|
|
||||||
throw e;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const permissions = await currentUser.app_role.getPermissions();
|
||||||
|
|
||||||
|
return !!permissions.find((p) => p.name === permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = class SearchService {
|
module.exports = class SearchService {
|
||||||
static async search(searchQuery, currentUser , organizationId, globalAccess) {
|
static async search(searchQuery, currentUser, globalAccess) {
|
||||||
try {
|
const normalizedSearchQuery = normalizeSearchQuery(searchQuery);
|
||||||
if (!searchQuery) {
|
const likeSearchQuery = `%${escapeLikePattern(normalizedSearchQuery)}%`;
|
||||||
throw new ValidationError('iam.errors.searchQueryRequired');
|
const lowerSearchQuery = normalizedSearchQuery.toLowerCase();
|
||||||
}
|
|
||||||
const tableColumns = {
|
const tableColumns = {
|
||||||
|
|
||||||
|
|
||||||
@ -427,72 +455,87 @@ module.exports = class SearchService {
|
|||||||
|
|
||||||
let allFoundRecords = [];
|
let allFoundRecords = [];
|
||||||
|
|
||||||
for (const tableName in tableColumns) {
|
for (const [tableName, attributesToSearch] of Object.entries(tableColumns)) {
|
||||||
if (tableColumns.hasOwnProperty(tableName)) {
|
const model = db[tableName];
|
||||||
const attributesToSearch = tableColumns[tableName];
|
if (!model) {
|
||||||
const attributesIntToSearch = columnsInt[tableName] || [];
|
continue;
|
||||||
const whereCondition = {
|
}
|
||||||
[Op.or]: [
|
|
||||||
...attributesToSearch.map(attribute => ({
|
const attributesIntToSearch = columnsInt[tableName] || [];
|
||||||
[attribute]: {
|
const whereCondition = {
|
||||||
[Op.iLike] : `%${searchQuery}%`,
|
[Op.or]: [
|
||||||
},
|
...attributesToSearch.map(attribute => ({
|
||||||
})),
|
[attribute]: {
|
||||||
...attributesIntToSearch.map(attribute => (
|
[Op.iLike]: likeSearchQuery,
|
||||||
Sequelize.where(
|
},
|
||||||
Sequelize.cast(Sequelize.col(`${tableName}.${attribute}`), 'varchar'),
|
})),
|
||||||
{ [Op.iLike]: `%${searchQuery}%` }
|
...attributesIntToSearch.map(attribute => (
|
||||||
)
|
Sequelize.where(
|
||||||
)),
|
Sequelize.cast(Sequelize.col(`${tableName}.${attribute}`), 'varchar'),
|
||||||
],
|
{ [Op.iLike]: likeSearchQuery }
|
||||||
|
)
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!globalAccess) {
|
||||||
|
const schoolId = getCurrentUserSchoolId(currentUser);
|
||||||
|
const rawAttributes = model.rawAttributes || {};
|
||||||
|
|
||||||
|
if (!schoolId) {
|
||||||
|
whereCondition.id = null;
|
||||||
|
} else if (tableName === 'schools') {
|
||||||
|
whereCondition.id = schoolId;
|
||||||
|
} else if (rawAttributes.schoolId) {
|
||||||
|
whereCondition.schoolId = schoolId;
|
||||||
|
} else if (rawAttributes.schoolsId) {
|
||||||
|
whereCondition.schoolsId = schoolId;
|
||||||
|
} else {
|
||||||
|
whereCondition.id = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasPermission = await checkPermissions(`READ_${tableName.toUpperCase()}`, currentUser);
|
||||||
|
if (!hasPermission) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const foundRecords = await model.findAll({
|
||||||
|
where: whereCondition,
|
||||||
|
attributes: [...new Set([...attributesToSearch, 'id', ...attributesIntToSearch])],
|
||||||
|
limit: MAX_RESULTS_PER_TABLE,
|
||||||
|
});
|
||||||
|
|
||||||
|
const modifiedRecords = foundRecords.map((record) => {
|
||||||
|
const matchAttribute = [];
|
||||||
|
|
||||||
|
for (const attribute of attributesToSearch) {
|
||||||
|
const value = record[attribute];
|
||||||
|
if (typeof value === 'string' && value.toLowerCase().includes(lowerSearchQuery)) {
|
||||||
|
matchAttribute.push(attribute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const attribute of attributesIntToSearch) {
|
||||||
|
const castedValue = String(record[attribute] ?? '');
|
||||||
|
if (castedValue.toLowerCase().includes(lowerSearchQuery)) {
|
||||||
|
matchAttribute.push(attribute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...record.get(),
|
||||||
|
matchAttribute,
|
||||||
|
tableName,
|
||||||
};
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
allFoundRecords = allFoundRecords.concat(modifiedRecords);
|
||||||
if (!globalAccess && tableName !== 'organizations' && organizationId) {
|
if (allFoundRecords.length >= MAX_TOTAL_SEARCH_RESULTS) {
|
||||||
whereCondition.organizationId = organizationId;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const hasPermission = await checkPermissions(`READ_${tableName.toUpperCase()}`, currentUser);
|
|
||||||
if (!hasPermission) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const foundRecords = await db[tableName].findAll({
|
|
||||||
where: whereCondition,
|
|
||||||
attributes: [...tableColumns[tableName], 'id', ...attributesIntToSearch],
|
|
||||||
});
|
|
||||||
|
|
||||||
const modifiedRecords = foundRecords.map((record) => {
|
|
||||||
const matchAttribute = [];
|
|
||||||
|
|
||||||
for (const attribute of attributesToSearch) {
|
|
||||||
if (record[attribute]?.toLowerCase()?.includes(searchQuery.toLowerCase())) {
|
|
||||||
matchAttribute.push(attribute);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const attribute of attributesIntToSearch) {
|
|
||||||
const castedValue = String(record[attribute]);
|
|
||||||
if (castedValue && castedValue.toLowerCase().includes(searchQuery.toLowerCase())) {
|
|
||||||
matchAttribute.push(attribute);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...record.get(),
|
|
||||||
matchAttribute,
|
|
||||||
tableName,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
allFoundRecords = allFoundRecords.concat(modifiedRecords);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return allFoundRecords;
|
return allFoundRecords.slice(0, MAX_TOTAL_SEARCH_RESULTS);
|
||||||
} catch (error) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user