180 lines
6.1 KiB
TypeScript
180 lines
6.1 KiB
TypeScript
import { Request, Response } from 'express';
|
|
import SystemSettings from '../models/SystemSettings.js';
|
|
import User from '../models/User.js';
|
|
import OrganizationMember from '../models/OrganizationMember.js';
|
|
import Organization from '../models/Organization.js';
|
|
import path from 'path';
|
|
import fs from 'fs';
|
|
import os from 'os';
|
|
|
|
export const getSettings = async (req: Request, res: Response) => {
|
|
try {
|
|
let settings = await SystemSettings.findOne({ settingsId: 'global' });
|
|
|
|
if (!settings) {
|
|
// Create default if not exists
|
|
settings = await SystemSettings.create({
|
|
settingsId: 'global',
|
|
appName: 'GPI',
|
|
appSubtitle: 'Gestão de Pintura Industrial'
|
|
});
|
|
}
|
|
|
|
res.json(settings);
|
|
} catch (error) {
|
|
console.error('Error fetching system settings:', error);
|
|
res.status(500).json({ error: 'Erro ao buscar configurações do sistema' });
|
|
}
|
|
};
|
|
|
|
export const updateSettings = async (req: Request, res: Response) => {
|
|
try {
|
|
const { appName, appSubtitle, appLogoUrl } = req.body;
|
|
|
|
const settings = await SystemSettings.findOneAndUpdate(
|
|
{ settingsId: 'global' },
|
|
{
|
|
appName,
|
|
appSubtitle,
|
|
appLogoUrl,
|
|
updatedBy: req.appUser?.email
|
|
},
|
|
{ new: true, upsert: true } // Create if not exists
|
|
);
|
|
|
|
console.log(`⚙️ System Settings updated by ${req.appUser?.email}`);
|
|
res.json(settings);
|
|
} catch (error) {
|
|
console.error('Error updating system settings:', error);
|
|
res.status(500).json({ error: 'Erro ao atualizar configurações do sistema' });
|
|
}
|
|
};
|
|
|
|
|
|
export const serveLogo = async (req: Request, res: Response) => {
|
|
try {
|
|
const { filename } = req.params as { filename: string };
|
|
|
|
// Check tmp dir first (Serverless/Netlify uploads)
|
|
const tmpPath = path.join(os.tmpdir(), 'uploads', filename);
|
|
// Check local dir (Development)
|
|
const localPath = path.join(process.cwd(), 'uploads', filename);
|
|
|
|
if (fs.existsSync(tmpPath)) {
|
|
res.sendFile(tmpPath);
|
|
} else if (fs.existsSync(localPath)) {
|
|
res.sendFile(localPath);
|
|
} else {
|
|
console.error(`Logo file not found in tmp or local: ${filename}`);
|
|
res.status(404).json({ error: 'Imagem não encontrada' });
|
|
}
|
|
} catch (error) {
|
|
console.error('Error serving logo:', error);
|
|
res.status(500).json({ error: 'Erro ao processar imagem' });
|
|
}
|
|
};
|
|
|
|
export const uploadLogo = async (req: Request, res: Response) => {
|
|
try {
|
|
if (!req.file) {
|
|
return res.status(400).json({ error: 'Nenhum arquivo enviado.' });
|
|
}
|
|
|
|
// Return the API URL instead of static path
|
|
// This ensures requests go through /api proxy and we control serving
|
|
const fileUrl = `/api/system-settings/logo-image/${req.file.filename}`;
|
|
|
|
res.json({ url: fileUrl });
|
|
} catch (error) {
|
|
console.error('Error uploading logo:', error);
|
|
res.status(500).json({ error: 'Erro ao fazer upload do logo.' });
|
|
}
|
|
};
|
|
|
|
// Global Admin Functions
|
|
export const getGlobalUsers = async (req: Request, res: Response) => {
|
|
try {
|
|
const users = await User.find({}).sort({ createdAt: -1 });
|
|
res.json(users);
|
|
} catch (error) {
|
|
console.error('Error getting global users:', error);
|
|
res.status(500).json({ error: 'Erro ao buscar usuários globais.' });
|
|
}
|
|
};
|
|
|
|
export const getGlobalOrganizations = async (req: Request, res: Response) => {
|
|
try {
|
|
// Aggregate members to group by org and get full member lists
|
|
const organizations = await OrganizationMember.aggregate([
|
|
{
|
|
$group: {
|
|
_id: '$organizationId',
|
|
members: {
|
|
$push: {
|
|
name: '$name',
|
|
email: '$email',
|
|
role: '$role',
|
|
clerkUserId: '$clerkUserId',
|
|
isBanned: '$isBanned'
|
|
}
|
|
},
|
|
lastActive: { $max: '$updatedAt' }
|
|
}
|
|
},
|
|
{
|
|
$lookup: {
|
|
from: 'organizations', // Ensure this matches the collection name of Organization model
|
|
localField: '_id',
|
|
foreignField: 'clerkId',
|
|
as: 'orgDetails'
|
|
}
|
|
},
|
|
{
|
|
$unwind: {
|
|
path: '$orgDetails',
|
|
preserveNullAndEmptyArrays: true
|
|
}
|
|
},
|
|
{
|
|
$project: {
|
|
_id: 1,
|
|
lastActive: 1,
|
|
members: 1,
|
|
memberCount: { $size: '$members' },
|
|
isBanned: { $ifNull: ['$orgDetails.isBanned', false] },
|
|
name: { $ifNull: ['$orgDetails.name', ''] }
|
|
}
|
|
},
|
|
{ $sort: { memberCount: -1 } }
|
|
]);
|
|
|
|
res.json(organizations);
|
|
} catch (error) {
|
|
console.error('Error getting global organizations:', error);
|
|
res.status(500).json({ error: 'Erro ao buscar organizações globais.' });
|
|
}
|
|
};
|
|
|
|
export const toggleOrganizationBan = async (req: Request, res: Response) => {
|
|
try {
|
|
const { organizationId, isBanned } = req.body;
|
|
|
|
if (!organizationId) {
|
|
return res.status(400).json({ error: 'ID da organização é obrigatório.' });
|
|
}
|
|
|
|
// Upsert the Organization record
|
|
const org = await Organization.findOneAndUpdate(
|
|
{ clerkId: organizationId },
|
|
{ isBanned: isBanned },
|
|
{ new: true, upsert: true }
|
|
);
|
|
|
|
console.log(`Organization ${organizationId} ban status set to ${isBanned} by ${req.appUser?.email}`);
|
|
res.json(org);
|
|
} catch (error) {
|
|
console.error('Error toggling organization ban:', error);
|
|
res.status(500).json({ error: 'Erro ao atualizar status da organização.' });
|
|
}
|
|
};
|