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:
@@ -2,106 +2,50 @@ import { db } from '../config/database.js';
|
||||
import { todos, todoUsers, notes, projects, companies, users } from '../db/schema.js';
|
||||
import { eq, desc, ilike, or, and, inArray } from 'drizzle-orm';
|
||||
import { NotFoundError } from '../utils/errors.js';
|
||||
import { getAccessibleResourceIds } from '../middlewares/auth/resourceAccessMiddleware.js';
|
||||
|
||||
/**
|
||||
* Get all todos
|
||||
* Optionally filter by search, project, company, assigned user, or status
|
||||
* For members: returns only todos they are assigned to
|
||||
*/
|
||||
export const getAllTodos = async (filters = {}) => {
|
||||
export const getAllTodos = async (filters = {}, userId = null, userRole = null) => {
|
||||
const { searchTerm, projectId, companyId, assignedTo, status, priority } = filters;
|
||||
|
||||
// If filtering by assignedTo, we need to join with todo_users
|
||||
// Pre membera filtruj len todos kde je priradeny
|
||||
let accessibleTodoIds = null;
|
||||
if (userRole && userRole !== 'admin' && userId) {
|
||||
accessibleTodoIds = await getAccessibleResourceIds('todo', userId);
|
||||
// Ak member nema pristup k ziadnym todos, vrat prazdne pole
|
||||
if (accessibleTodoIds.length === 0) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// Build query conditions
|
||||
const conditions = [];
|
||||
|
||||
// Member access filter - only todos they are assigned to
|
||||
if (accessibleTodoIds !== null) {
|
||||
conditions.push(inArray(todos.id, accessibleTodoIds));
|
||||
}
|
||||
|
||||
// If filtering by assignedTo, we need additional filter
|
||||
if (assignedTo) {
|
||||
const todoIdsWithUser = await db
|
||||
.select({ todoId: todoUsers.todoId })
|
||||
.from(todoUsers)
|
||||
.where(eq(todoUsers.userId, assignedTo));
|
||||
|
||||
const todoIds = todoIdsWithUser.map((row) => row.todoId);
|
||||
const assignedTodoIds = todoIdsWithUser.map((row) => row.todoId);
|
||||
|
||||
if (todoIds.length === 0) {
|
||||
if (assignedTodoIds.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
let query = db.select().from(todos).where(inArray(todos.id, todoIds));
|
||||
|
||||
const conditions = [];
|
||||
|
||||
if (searchTerm) {
|
||||
conditions.push(
|
||||
or(
|
||||
ilike(todos.title, `%${searchTerm}%`),
|
||||
ilike(todos.description, `%${searchTerm}%`)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (projectId) {
|
||||
conditions.push(eq(todos.projectId, projectId));
|
||||
}
|
||||
|
||||
if (companyId) {
|
||||
conditions.push(eq(todos.companyId, companyId));
|
||||
}
|
||||
|
||||
if (status) {
|
||||
conditions.push(eq(todos.status, status));
|
||||
}
|
||||
|
||||
if (priority) {
|
||||
conditions.push(eq(todos.priority, priority));
|
||||
}
|
||||
|
||||
if (conditions.length > 0) {
|
||||
query = query.where(and(...conditions));
|
||||
}
|
||||
|
||||
const result = await query.orderBy(desc(todos.createdAt));
|
||||
|
||||
// Fetch assigned users for all todos
|
||||
if (result.length > 0) {
|
||||
const todoIds = result.map(todo => todo.id);
|
||||
const assignedUsersData = await db
|
||||
.select({
|
||||
todoId: todoUsers.todoId,
|
||||
userId: users.id,
|
||||
username: users.username,
|
||||
firstName: users.firstName,
|
||||
lastName: users.lastName,
|
||||
})
|
||||
.from(todoUsers)
|
||||
.innerJoin(users, eq(todoUsers.userId, users.id))
|
||||
.where(inArray(todoUsers.todoId, todoIds));
|
||||
|
||||
// Group assigned users by todoId
|
||||
const usersByTodoId = {};
|
||||
for (const row of assignedUsersData) {
|
||||
if (!usersByTodoId[row.todoId]) {
|
||||
usersByTodoId[row.todoId] = [];
|
||||
}
|
||||
usersByTodoId[row.todoId].push({
|
||||
id: row.userId,
|
||||
username: row.username,
|
||||
firstName: row.firstName,
|
||||
lastName: row.lastName,
|
||||
});
|
||||
}
|
||||
|
||||
// Attach assigned users to each todo
|
||||
return result.map(todo => ({
|
||||
...todo,
|
||||
assignedUsers: usersByTodoId[todo.id] || [],
|
||||
}));
|
||||
}
|
||||
|
||||
return result;
|
||||
conditions.push(inArray(todos.id, assignedTodoIds));
|
||||
}
|
||||
|
||||
// No assignedTo filter - simple query
|
||||
let query = db.select().from(todos);
|
||||
|
||||
const conditions = [];
|
||||
|
||||
if (searchTerm) {
|
||||
conditions.push(
|
||||
or(
|
||||
@@ -127,6 +71,8 @@ export const getAllTodos = async (filters = {}) => {
|
||||
conditions.push(eq(todos.priority, priority));
|
||||
}
|
||||
|
||||
let query = db.select().from(todos);
|
||||
|
||||
if (conditions.length > 0) {
|
||||
query = query.where(and(...conditions));
|
||||
}
|
||||
@@ -135,18 +81,18 @@ export const getAllTodos = async (filters = {}) => {
|
||||
|
||||
// Fetch assigned users for all todos
|
||||
if (result.length > 0) {
|
||||
const todoIds = result.map(todo => todo.id);
|
||||
const resultTodoIds = result.map(todo => todo.id);
|
||||
const assignedUsersData = await db
|
||||
.select({
|
||||
todoId: todoUsers.todoId,
|
||||
userId: users.id,
|
||||
odUserId: users.id,
|
||||
username: users.username,
|
||||
firstName: users.firstName,
|
||||
lastName: users.lastName,
|
||||
})
|
||||
.from(todoUsers)
|
||||
.innerJoin(users, eq(todoUsers.userId, users.id))
|
||||
.where(inArray(todoUsers.todoId, todoIds));
|
||||
.where(inArray(todoUsers.todoId, resultTodoIds));
|
||||
|
||||
// Group assigned users by todoId
|
||||
const usersByTodoId = {};
|
||||
@@ -155,7 +101,7 @@ export const getAllTodos = async (filters = {}) => {
|
||||
usersByTodoId[row.todoId] = [];
|
||||
}
|
||||
usersByTodoId[row.todoId].push({
|
||||
id: row.userId,
|
||||
id: row.odUserId,
|
||||
username: row.username,
|
||||
firstName: row.firstName,
|
||||
lastName: row.lastName,
|
||||
|
||||
Reference in New Issue
Block a user