feat: Add creator info, team management for companies, and member access control
- Add creator info (username) to companies, projects, and notes responses - Add company_users table for team management on companies - Add resourceAccessMiddleware for member access control - Members can only see resources they are directly assigned to - Companies, projects, and todos are now filtered by user assignments - Add personal contacts feature 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import { db } from '../config/database.js';
|
||||
import { companies, companyReminders } from '../db/schema.js';
|
||||
import { eq, desc, sql, and, lte, gte, isNull, or } from 'drizzle-orm';
|
||||
import { eq, desc, sql, and, lte, gte, isNull, or, inArray } from 'drizzle-orm';
|
||||
import { NotFoundError, BadRequestError } from '../utils/errors.js';
|
||||
import { getAccessibleResourceIds } from '../middlewares/auth/resourceAccessMiddleware.js';
|
||||
|
||||
const ensureCompanyExists = async (companyId) => {
|
||||
const [company] = await db
|
||||
@@ -105,8 +106,17 @@ export const deleteReminder = async (companyId, reminderId) => {
|
||||
return { success: true, message: 'Reminder bol odstránený' };
|
||||
};
|
||||
|
||||
export const getReminderSummary = async () => {
|
||||
const [row] = await db
|
||||
export const getReminderSummary = async (userId = null, userRole = null) => {
|
||||
// Pre membera filtruj len pristupne firmy
|
||||
let accessibleCompanyIds = null;
|
||||
if (userRole && userRole !== 'admin' && userId) {
|
||||
accessibleCompanyIds = await getAccessibleResourceIds('company', userId);
|
||||
if (accessibleCompanyIds.length === 0) {
|
||||
return { total: 0, active: 0, completed: 0 };
|
||||
}
|
||||
}
|
||||
|
||||
let query = db
|
||||
.select({
|
||||
total: sql`COUNT(*)::int`,
|
||||
active: sql`COUNT(*) FILTER (WHERE ${companyReminders.isChecked} = false)::int`,
|
||||
@@ -114,6 +124,12 @@ export const getReminderSummary = async () => {
|
||||
})
|
||||
.from(companyReminders);
|
||||
|
||||
if (accessibleCompanyIds !== null) {
|
||||
query = query.where(inArray(companyReminders.companyId, accessibleCompanyIds));
|
||||
}
|
||||
|
||||
const [row] = await query;
|
||||
|
||||
return {
|
||||
total: row?.total ?? 0,
|
||||
active: row?.active ?? 0,
|
||||
@@ -121,15 +137,30 @@ export const getReminderSummary = async () => {
|
||||
};
|
||||
};
|
||||
|
||||
export const getReminderCountsByCompany = async () => {
|
||||
const rows = await db
|
||||
export const getReminderCountsByCompany = async (userId = null, userRole = null) => {
|
||||
// Pre membera filtruj len pristupne firmy
|
||||
let accessibleCompanyIds = null;
|
||||
if (userRole && userRole !== 'admin' && userId) {
|
||||
accessibleCompanyIds = await getAccessibleResourceIds('company', userId);
|
||||
if (accessibleCompanyIds.length === 0) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
let query = db
|
||||
.select({
|
||||
companyId: companyReminders.companyId,
|
||||
total: sql`COUNT(*)::int`,
|
||||
active: sql`COUNT(*) FILTER (WHERE ${companyReminders.isChecked} = false)::int`,
|
||||
completed: sql`COUNT(*) FILTER (WHERE ${companyReminders.isChecked} = true)::int`,
|
||||
})
|
||||
.from(companyReminders)
|
||||
.from(companyReminders);
|
||||
|
||||
if (accessibleCompanyIds !== null) {
|
||||
query = query.where(inArray(companyReminders.companyId, accessibleCompanyIds));
|
||||
}
|
||||
|
||||
const rows = await query
|
||||
.groupBy(companyReminders.companyId)
|
||||
.orderBy(desc(companyReminders.companyId));
|
||||
|
||||
@@ -140,12 +171,32 @@ export const getReminderCountsByCompany = async () => {
|
||||
* Get upcoming reminders for dashboard
|
||||
* Returns reminders due within the next 5 days that are not checked
|
||||
* Includes company name for display
|
||||
* For members: returns only reminders from companies they are assigned to
|
||||
*/
|
||||
export const getUpcomingReminders = async () => {
|
||||
export const getUpcomingReminders = async (userId = null, userRole = null) => {
|
||||
// Pre membera filtruj len pristupne firmy
|
||||
let accessibleCompanyIds = null;
|
||||
if (userRole && userRole !== 'admin' && userId) {
|
||||
accessibleCompanyIds = await getAccessibleResourceIds('company', userId);
|
||||
if (accessibleCompanyIds.length === 0) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
const fiveDaysFromNow = new Date();
|
||||
fiveDaysFromNow.setDate(fiveDaysFromNow.getDate() + 5);
|
||||
|
||||
const conditions = [
|
||||
eq(companyReminders.isChecked, false),
|
||||
lte(companyReminders.dueDate, fiveDaysFromNow),
|
||||
gte(companyReminders.dueDate, now)
|
||||
];
|
||||
|
||||
if (accessibleCompanyIds !== null) {
|
||||
conditions.push(inArray(companyReminders.companyId, accessibleCompanyIds));
|
||||
}
|
||||
|
||||
const reminders = await db
|
||||
.select({
|
||||
id: companyReminders.id,
|
||||
@@ -158,13 +209,7 @@ export const getUpcomingReminders = async () => {
|
||||
})
|
||||
.from(companyReminders)
|
||||
.leftJoin(companies, eq(companyReminders.companyId, companies.id))
|
||||
.where(
|
||||
and(
|
||||
eq(companyReminders.isChecked, false),
|
||||
lte(companyReminders.dueDate, fiveDaysFromNow),
|
||||
gte(companyReminders.dueDate, now)
|
||||
)
|
||||
)
|
||||
.where(and(...conditions))
|
||||
.orderBy(companyReminders.dueDate);
|
||||
|
||||
return reminders;
|
||||
|
||||
Reference in New Issue
Block a user