Projects view by user
This commit is contained in:
@@ -17,6 +17,7 @@ export interface User {
|
|||||||
description: string;
|
description: string;
|
||||||
permissions: Record<string, Record<string, boolean>>;
|
permissions: Record<string, Record<string, boolean>>;
|
||||||
};
|
};
|
||||||
|
project_id: string | null;
|
||||||
is_active: boolean;
|
is_active: boolean;
|
||||||
last_login: string | null;
|
last_login: string | null;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
@@ -28,6 +29,7 @@ export interface CreateUserInput {
|
|||||||
password: string;
|
password: string;
|
||||||
name: string;
|
name: string;
|
||||||
role_id: string;
|
role_id: string;
|
||||||
|
project_id?: string | null;
|
||||||
is_active?: boolean;
|
is_active?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,6 +37,7 @@ export interface UpdateUserInput {
|
|||||||
email?: string;
|
email?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
role_id?: string;
|
role_id?: string;
|
||||||
|
project_id?: string | null;
|
||||||
is_active?: boolean;
|
is_active?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ interface User {
|
|||||||
email: string;
|
email: string;
|
||||||
roleId: string;
|
roleId: string;
|
||||||
roleName: string;
|
roleName: string;
|
||||||
|
projectId: string | null;
|
||||||
status: "ACTIVE" | "INACTIVE";
|
status: "ACTIVE" | "INACTIVE";
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
}
|
}
|
||||||
@@ -65,6 +66,7 @@ export default function UsersPage() {
|
|||||||
email: apiUser.email,
|
email: apiUser.email,
|
||||||
roleId: apiUser.role_id,
|
roleId: apiUser.role_id,
|
||||||
roleName: apiUser.role?.name || '',
|
roleName: apiUser.role?.name || '',
|
||||||
|
projectId: apiUser.project_id || null,
|
||||||
status: apiUser.is_active ? "ACTIVE" : "INACTIVE",
|
status: apiUser.is_active ? "ACTIVE" : "INACTIVE",
|
||||||
createdAt: new Date(apiUser.created_at).toISOString().slice(0, 10)
|
createdAt: new Date(apiUser.created_at).toISOString().slice(0, 10)
|
||||||
}));
|
}));
|
||||||
@@ -126,6 +128,7 @@ export default function UsersPage() {
|
|||||||
email: form.email,
|
email: form.email,
|
||||||
name: form.name.trim(),
|
name: form.name.trim(),
|
||||||
role_id: form.roleId,
|
role_id: form.roleId,
|
||||||
|
project_id: form.projectId || null,
|
||||||
is_active: form.status === "ACTIVE",
|
is_active: form.status === "ACTIVE",
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -136,6 +139,7 @@ export default function UsersPage() {
|
|||||||
password: form.password!,
|
password: form.password!,
|
||||||
name: form.name.trim(),
|
name: form.name.trim(),
|
||||||
role_id: form.roleId,
|
role_id: form.roleId,
|
||||||
|
project_id: form.projectId || null,
|
||||||
is_active: form.status === "ACTIVE",
|
is_active: form.status === "ACTIVE",
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -221,7 +225,7 @@ export default function UsersPage() {
|
|||||||
name: user.name,
|
name: user.name,
|
||||||
email: user.email,
|
email: user.email,
|
||||||
roleId: user.roleId,
|
roleId: user.roleId,
|
||||||
projectId: "",
|
projectId: user.projectId || "",
|
||||||
status: user.status,
|
status: user.status,
|
||||||
createdAt: user.createdAt,
|
createdAt: user.createdAt,
|
||||||
password: ""
|
password: ""
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Request, Response } from 'express';
|
import { Response } from 'express';
|
||||||
|
import { AuthenticatedRequest } from '../types';
|
||||||
import * as concentratorService from '../services/concentrator.service';
|
import * as concentratorService from '../services/concentrator.service';
|
||||||
import { CreateConcentratorInput, UpdateConcentratorInput } from '../validators/concentrator.validator';
|
import { CreateConcentratorInput, UpdateConcentratorInput } from '../validators/concentrator.validator';
|
||||||
|
|
||||||
@@ -7,13 +8,14 @@ import { CreateConcentratorInput, UpdateConcentratorInput } from '../validators/
|
|||||||
* Get all concentrators with optional filters and pagination
|
* Get all concentrators with optional filters and pagination
|
||||||
* Query params: project_id, status, page, limit, sortBy, sortOrder
|
* Query params: project_id, status, page, limit, sortBy, sortOrder
|
||||||
*/
|
*/
|
||||||
export async function getAll(req: Request, res: Response): Promise<void> {
|
export async function getAll(req: AuthenticatedRequest, res: Response): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const { project_id, status, page, limit, sortBy, sortOrder } = req.query;
|
const { project_id, status, type, page, limit, sortBy, sortOrder } = req.query;
|
||||||
|
|
||||||
const filters: concentratorService.ConcentratorFilters = {};
|
const filters: concentratorService.ConcentratorFilters = {};
|
||||||
if (project_id) filters.project_id = project_id as string;
|
if (project_id) filters.project_id = project_id as string;
|
||||||
if (status) filters.status = status as string;
|
if (status) filters.status = status as string;
|
||||||
|
if (type) filters.type = type as concentratorService.ConcentratorType;
|
||||||
|
|
||||||
const pagination: concentratorService.PaginationOptions = {
|
const pagination: concentratorService.PaginationOptions = {
|
||||||
page: page ? parseInt(page as string, 10) : 1,
|
page: page ? parseInt(page as string, 10) : 1,
|
||||||
@@ -22,7 +24,13 @@ export async function getAll(req: Request, res: Response): Promise<void> {
|
|||||||
sortOrder: sortOrder as 'asc' | 'desc',
|
sortOrder: sortOrder as 'asc' | 'desc',
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = await concentratorService.getAll(filters, pagination);
|
// Pass user info for role-based filtering
|
||||||
|
const requestingUser = req.user ? {
|
||||||
|
roleName: req.user.roleName,
|
||||||
|
projectId: req.user.projectId
|
||||||
|
} : undefined;
|
||||||
|
|
||||||
|
const result = await concentratorService.getAll(filters, pagination, requestingUser);
|
||||||
|
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
success: true,
|
success: true,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import * as readingService from '../services/reading.service';
|
|||||||
* List all meters with pagination and optional filtering
|
* List all meters with pagination and optional filtering
|
||||||
* Query params: page, pageSize, concentrator_id, project_id, status, type, search
|
* Query params: page, pageSize, concentrator_id, project_id, status, type, search
|
||||||
*/
|
*/
|
||||||
export async function getAll(req: Request, res: Response): Promise<void> {
|
export async function getAll(req: AuthenticatedRequest, res: Response): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const page = parseInt(req.query.page as string, 10) || 1;
|
const page = parseInt(req.query.page as string, 10) || 1;
|
||||||
const pageSize = Math.min(parseInt(req.query.pageSize as string, 10) || 50, 1000);
|
const pageSize = Math.min(parseInt(req.query.pageSize as string, 10) || 50, 1000);
|
||||||
@@ -35,7 +35,13 @@ export async function getAll(req: Request, res: Response): Promise<void> {
|
|||||||
filters.search = req.query.search as string;
|
filters.search = req.query.search as string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await meterService.getAll(filters, { page, pageSize });
|
// Pass user info for role-based filtering
|
||||||
|
const requestingUser = req.user ? {
|
||||||
|
roleName: req.user.roleName,
|
||||||
|
projectId: req.user.projectId
|
||||||
|
} : undefined;
|
||||||
|
|
||||||
|
const result = await meterService.getAll(filters, { page, pageSize }, requestingUser);
|
||||||
|
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
success: true,
|
success: true,
|
||||||
|
|||||||
@@ -68,11 +68,13 @@ export interface PaginatedResult<T> {
|
|||||||
* Get all concentrators with optional filters and pagination
|
* Get all concentrators with optional filters and pagination
|
||||||
* @param filters - Optional filter criteria
|
* @param filters - Optional filter criteria
|
||||||
* @param pagination - Optional pagination options
|
* @param pagination - Optional pagination options
|
||||||
|
* @param requestingUser - User making the request (for role-based filtering)
|
||||||
* @returns Paginated list of concentrators
|
* @returns Paginated list of concentrators
|
||||||
*/
|
*/
|
||||||
export async function getAll(
|
export async function getAll(
|
||||||
filters?: ConcentratorFilters,
|
filters?: ConcentratorFilters,
|
||||||
pagination?: PaginationOptions
|
pagination?: PaginationOptions,
|
||||||
|
requestingUser?: { roleName: string; projectId?: string | null }
|
||||||
): Promise<PaginatedResult<Concentrator>> {
|
): Promise<PaginatedResult<Concentrator>> {
|
||||||
const page = pagination?.page || 1;
|
const page = pagination?.page || 1;
|
||||||
const limit = pagination?.limit || 10;
|
const limit = pagination?.limit || 10;
|
||||||
@@ -85,7 +87,15 @@ export async function getAll(
|
|||||||
const params: unknown[] = [];
|
const params: unknown[] = [];
|
||||||
let paramIndex = 1;
|
let paramIndex = 1;
|
||||||
|
|
||||||
if (filters?.project_id) {
|
// Role-based filtering: OPERATOR users can only see their assigned project
|
||||||
|
if (requestingUser && requestingUser.roleName !== 'ADMIN' && requestingUser.projectId) {
|
||||||
|
conditions.push(`project_id = $${paramIndex}`);
|
||||||
|
params.push(requestingUser.projectId);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Additional filter by project_id (only applies if user is ADMIN or no user context)
|
||||||
|
if (filters?.project_id && (!requestingUser || requestingUser.roleName === 'ADMIN')) {
|
||||||
conditions.push(`project_id = $${paramIndex}`);
|
conditions.push(`project_id = $${paramIndex}`);
|
||||||
params.push(filters.project_id);
|
params.push(filters.project_id);
|
||||||
paramIndex++;
|
paramIndex++;
|
||||||
|
|||||||
@@ -92,10 +92,14 @@ export interface UpdateMeterInput {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all meters with optional filtering and pagination
|
* Get all meters with optional filtering and pagination
|
||||||
|
* @param filters - Optional filter criteria
|
||||||
|
* @param pagination - Optional pagination options
|
||||||
|
* @param requestingUser - User making the request (for role-based filtering)
|
||||||
*/
|
*/
|
||||||
export async function getAll(
|
export async function getAll(
|
||||||
filters?: MeterFilters,
|
filters?: MeterFilters,
|
||||||
pagination?: PaginationParams
|
pagination?: PaginationParams,
|
||||||
|
requestingUser?: { roleName: string; projectId?: string | null }
|
||||||
): Promise<PaginatedResult<MeterWithDetails>> {
|
): Promise<PaginatedResult<MeterWithDetails>> {
|
||||||
const page = pagination?.page || 1;
|
const page = pagination?.page || 1;
|
||||||
const pageSize = pagination?.pageSize || 50;
|
const pageSize = pagination?.pageSize || 50;
|
||||||
@@ -105,13 +109,21 @@ export async function getAll(
|
|||||||
const params: unknown[] = [];
|
const params: unknown[] = [];
|
||||||
let paramIndex = 1;
|
let paramIndex = 1;
|
||||||
|
|
||||||
|
// Role-based filtering: OPERATOR users can only see meters from their assigned project
|
||||||
|
if (requestingUser && requestingUser.roleName !== 'ADMIN' && requestingUser.projectId) {
|
||||||
|
conditions.push(`c.project_id = $${paramIndex}`);
|
||||||
|
params.push(requestingUser.projectId);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
if (filters?.concentrator_id) {
|
if (filters?.concentrator_id) {
|
||||||
conditions.push(`m.concentrator_id = $${paramIndex}`);
|
conditions.push(`m.concentrator_id = $${paramIndex}`);
|
||||||
params.push(filters.concentrator_id);
|
params.push(filters.concentrator_id);
|
||||||
paramIndex++;
|
paramIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters?.project_id) {
|
// Additional filter by project_id (only applies if user is ADMIN or no user context)
|
||||||
|
if (filters?.project_id && (!requestingUser || requestingUser.roleName === 'ADMIN')) {
|
||||||
conditions.push(`c.project_id = $${paramIndex}`);
|
conditions.push(`c.project_id = $${paramIndex}`);
|
||||||
params.push(filters.project_id);
|
params.push(filters.project_id);
|
||||||
paramIndex++;
|
paramIndex++;
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ export async function getAll(
|
|||||||
u.role_id,
|
u.role_id,
|
||||||
r.name as role_name,
|
r.name as role_name,
|
||||||
r.description as role_description,
|
r.description as role_description,
|
||||||
|
u.project_id,
|
||||||
u.is_active,
|
u.is_active,
|
||||||
u.last_login,
|
u.last_login,
|
||||||
u.created_at,
|
u.created_at,
|
||||||
@@ -122,6 +123,7 @@ export async function getAll(
|
|||||||
updated_at: row.updated_at,
|
updated_at: row.updated_at,
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
|
project_id: row.project_id,
|
||||||
is_active: row.is_active,
|
is_active: row.is_active,
|
||||||
last_login: row.last_login,
|
last_login: row.last_login,
|
||||||
created_at: row.created_at,
|
created_at: row.created_at,
|
||||||
@@ -160,6 +162,7 @@ export async function getById(id: string): Promise<UserPublic | null> {
|
|||||||
r.name as role_name,
|
r.name as role_name,
|
||||||
r.description as role_description,
|
r.description as role_description,
|
||||||
r.permissions as role_permissions,
|
r.permissions as role_permissions,
|
||||||
|
u.project_id,
|
||||||
u.is_active,
|
u.is_active,
|
||||||
u.last_login,
|
u.last_login,
|
||||||
u.created_at,
|
u.created_at,
|
||||||
@@ -192,6 +195,7 @@ export async function getById(id: string): Promise<UserPublic | null> {
|
|||||||
updated_at: row.updated_at,
|
updated_at: row.updated_at,
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
|
project_id: row.project_id,
|
||||||
is_active: row.is_active,
|
is_active: row.is_active,
|
||||||
last_login: row.last_login,
|
last_login: row.last_login,
|
||||||
created_at: row.created_at,
|
created_at: row.created_at,
|
||||||
@@ -235,6 +239,7 @@ export async function create(data: {
|
|||||||
name: string;
|
name: string;
|
||||||
avatar_url?: string | null;
|
avatar_url?: string | null;
|
||||||
role_id: string;
|
role_id: string;
|
||||||
|
project_id?: string | null;
|
||||||
is_active?: boolean;
|
is_active?: boolean;
|
||||||
}): Promise<UserPublic> {
|
}): Promise<UserPublic> {
|
||||||
// Check if email already exists
|
// Check if email already exists
|
||||||
@@ -248,9 +253,9 @@ export async function create(data: {
|
|||||||
|
|
||||||
const result = await query(
|
const result = await query(
|
||||||
`
|
`
|
||||||
INSERT INTO users (email, password_hash, name, avatar_url, role_id, is_active)
|
INSERT INTO users (email, password_hash, name, avatar_url, role_id, project_id, is_active)
|
||||||
VALUES ($1, $2, $3, $4, $5, $6)
|
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||||
RETURNING id, email, name, avatar_url, role_id, is_active, last_login, created_at, updated_at
|
RETURNING id, email, name, avatar_url, role_id, project_id, is_active, last_login, created_at, updated_at
|
||||||
`,
|
`,
|
||||||
[
|
[
|
||||||
data.email.toLowerCase(),
|
data.email.toLowerCase(),
|
||||||
@@ -258,6 +263,7 @@ export async function create(data: {
|
|||||||
data.name,
|
data.name,
|
||||||
data.avatar_url ?? null,
|
data.avatar_url ?? null,
|
||||||
data.role_id,
|
data.role_id,
|
||||||
|
data.project_id ?? null,
|
||||||
data.is_active ?? true,
|
data.is_active ?? true,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
@@ -281,6 +287,7 @@ export async function update(
|
|||||||
name?: string;
|
name?: string;
|
||||||
avatar_url?: string | null;
|
avatar_url?: string | null;
|
||||||
role_id?: string;
|
role_id?: string;
|
||||||
|
project_id?: string | null;
|
||||||
is_active?: boolean;
|
is_active?: boolean;
|
||||||
}
|
}
|
||||||
): Promise<UserPublic | null> {
|
): Promise<UserPublic | null> {
|
||||||
@@ -327,6 +334,12 @@ export async function update(
|
|||||||
paramIndex++;
|
paramIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.project_id !== undefined) {
|
||||||
|
updates.push(`project_id = $${paramIndex}`);
|
||||||
|
params.push(data.project_id);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
if (data.is_active !== undefined) {
|
if (data.is_active !== undefined) {
|
||||||
updates.push(`is_active = $${paramIndex}`);
|
updates.push(`is_active = $${paramIndex}`);
|
||||||
params.push(data.is_active);
|
params.push(data.is_active);
|
||||||
|
|||||||
Reference in New Issue
Block a user