admin.service.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import { Injectable, NotFoundException, ForbiddenException, BadRequestException } from '@nestjs/common';
  2. import * as XLSX from 'xlsx';
  3. import { UserService } from '../user/user.service';
  4. import { TenantService } from '../tenant/tenant.service';
  5. @Injectable()
  6. export class AdminService {
  7. constructor(
  8. private readonly userService: UserService,
  9. private readonly tenantService: TenantService,
  10. ) { }
  11. async getTenantUsers(tenantId?: string, page?: number, limit?: number) {
  12. if (!tenantId) {
  13. return this.userService.findAll(page, limit);
  14. }
  15. return this.userService.findByTenantId(tenantId, page, limit);
  16. }
  17. async exportUsers(tenantId?: string): Promise<Buffer> {
  18. const { data: users } = tenantId
  19. ? await this.userService.findByTenantId(tenantId)
  20. : await this.userService.findAll();
  21. const worksheet = XLSX.utils.json_to_sheet(users.map(u => ({
  22. Username: u.username,
  23. DisplayName: u.displayName || '',
  24. IsAdmin: u.isAdmin ? 'Yes' : 'No',
  25. CreatedAt: u.createdAt,
  26. Password: '', // Placeholder for new users
  27. })));
  28. const workbook = XLSX.utils.book_new();
  29. XLSX.utils.book_append_sheet(workbook, worksheet, 'Users');
  30. return XLSX.write(workbook, { type: 'buffer', bookType: 'xlsx' });
  31. }
  32. async importUsers(tenantId?: string, file?: any) {
  33. if (!file) throw new BadRequestException('No file uploaded');
  34. const workbook = XLSX.read(file.buffer, { type: 'buffer' });
  35. const sheetName = workbook.SheetNames[0];
  36. const worksheet = workbook.Sheets[sheetName];
  37. const data = XLSX.utils.sheet_to_json(worksheet) as any[];
  38. const results = {
  39. success: 0,
  40. failed: 0,
  41. errors: [] as string[],
  42. };
  43. for (const row of data) {
  44. try {
  45. const username = (row.Username || row.username)?.toString();
  46. const displayName = (row.DisplayName || row.displayName || row.Name || row.name)?.toString();
  47. const password = (row.Password || row.password)?.toString();
  48. const isAdminStr = (row.IsAdmin || row.isAdmin || 'No').toString();
  49. const isAdmin = isAdminStr.toLowerCase() === 'yes' || isAdminStr === 'true' || isAdminStr === '1';
  50. if (!username) {
  51. throw new Error('Username is missing');
  52. }
  53. const existingUser = await this.userService.findOneByUsername(username);
  54. if (existingUser) {
  55. await this.userService.updateUser(existingUser.id, {
  56. displayName: displayName || existingUser.displayName,
  57. password: password || undefined,
  58. // We avoid changing isAdmin status via import for security unless explicitly required
  59. });
  60. } else {
  61. if (!password) {
  62. throw new Error(`Password missing for new user: ${username}`);
  63. }
  64. await this.userService.createUser(
  65. username,
  66. password,
  67. isAdmin,
  68. tenantId,
  69. displayName
  70. );
  71. }
  72. results.success++;
  73. } catch (e: any) {
  74. results.failed++;
  75. results.errors.push(`${row.Username || 'Unknown'}: ${e.message}`);
  76. }
  77. }
  78. return results;
  79. }
  80. async getTenantSettings(tenantId: string) {
  81. return this.tenantService.getSettings(tenantId);
  82. }
  83. async updateTenantSettings(tenantId: string, data: any) {
  84. return this.tenantService.updateSettings(tenantId, data);
  85. }
  86. // Notebook sharing approval and model assignments would go here
  87. async getPendingShares(tenantId: string) {
  88. // Mock implementation for pending shares to satisfy UI.
  89. // Needs proper schema/entity support in the future.
  90. return [];
  91. }
  92. }