create-crm-tmp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. package/bin/create-crm-tmp.js +93 -0
  2. package/package.json +25 -0
  3. package/template/.prettierignore +33 -0
  4. package/template/.prettierrc.json +25 -0
  5. package/template/README.md +173 -0
  6. package/template/eslint.config.mjs +18 -0
  7. package/template/exemple-contacts.csv +11 -0
  8. package/template/next.config.ts +8 -0
  9. package/template/package.json +64 -0
  10. package/template/postcss.config.mjs +7 -0
  11. package/template/prisma/migrations/20251126144728_init/migration.sql +78 -0
  12. package/template/prisma/migrations/20251126155204_add_user_roles/migration.sql +5 -0
  13. package/template/prisma/migrations/20251128095126_add_company_info/migration.sql +19 -0
  14. package/template/prisma/migrations/20251128123321_add_smtp_config/migration.sql +22 -0
  15. package/template/prisma/migrations/20251128132303_add_status/migration.sql +23 -0
  16. package/template/prisma/migrations/20251201102207_add_user_active/migration.sql +75 -0
  17. package/template/prisma/migrations/20251201105507_add_email_signature/migration.sql +2 -0
  18. package/template/prisma/migrations/20251201151122_add_tasks/migration.sql +45 -0
  19. package/template/prisma/migrations/20251202111854_add_task_reminder/migration.sql +2 -0
  20. package/template/prisma/migrations/20251202135859_add_google_meet_integration/migration.sql +27 -0
  21. package/template/prisma/migrations/20251203103317_add_meta_lead_integration/migration.sql +20 -0
  22. package/template/prisma/migrations/20251203104002_add_google_ads_integration/migration.sql +18 -0
  23. package/template/prisma/migrations/20251203112122_add_google_sheet_integration/migration.sql +32 -0
  24. package/template/prisma/migrations/20251203153853_allow_multiple_integration_configs/migration.sql +20 -0
  25. package/template/prisma/migrations/20251205141705_update_user_roles/migration.sql +12 -0
  26. package/template/prisma/migrations/20251205150000_add_commercial_and_telepro_assignment/migration.sql +21 -0
  27. package/template/prisma/migrations/20251205160000_add_interaction_logging/migration.sql +11 -0
  28. package/template/prisma/migrations/20251208090314_add_automatic_interaction_types/migration.sql +12 -0
  29. package/template/prisma/migrations/20251208094843_mg/migration.sql +14 -0
  30. package/template/prisma/migrations/20251208100000_add_company_support/migration.sql +14 -0
  31. package/template/prisma/migrations/20251208110000_add_templates/migration.sql +26 -0
  32. package/template/prisma/migrations/20251208141304_add_video_conference_task_type/migration.sql +2 -0
  33. package/template/prisma/migrations/20251209104759_add_internal_note_to_task/migration.sql +2 -0
  34. package/template/prisma/migrations/20251209134803_add_company_field/migration.sql +2 -0
  35. package/template/prisma/migrations/20251209150000_rename_company_to_company_name/migration.sql +3 -0
  36. package/template/prisma/migrations/20251209150016_add_email_tracking/migration.sql +21 -0
  37. package/template/prisma/migrations/20251209155908_add_notify_contact_to_task/migration.sql +2 -0
  38. package/template/prisma/migrations/20251210110019_add_appointment_types/migration.sql +10 -0
  39. package/template/prisma/migrations/20251210113928_add_contact_files/migration.sql +26 -0
  40. package/template/prisma/migrations/20251212132339_add_custom_roles/migration.sql +24 -0
  41. package/template/prisma/migrations/20251215104448_add_file_interaction_types/migration.sql +11 -0
  42. package/template/prisma/migrations/20251215145616_add_closing_reasons/migration.sql +12 -0
  43. package/template/prisma/migrations/20251216140850_add_log_users/migration.sql +25 -0
  44. package/template/prisma/migrations/20251216151000_rename_perdu_to_ferme/migration.sql +8 -0
  45. package/template/prisma/migrations/20251216162318_add_column_mappings_to_google_sheet/migration.sql +2 -0
  46. package/template/prisma/migrations/20251216185127_add_workflows/migration.sql +80 -0
  47. package/template/prisma/migrations/20251216192237_add_scheduled_workflow_actions/migration.sql +32 -0
  48. package/template/prisma/migrations/migration_lock.toml +3 -0
  49. package/template/prisma/schema.prisma +582 -0
  50. package/template/prisma.config.ts +14 -0
  51. package/template/src/app/(auth)/invite/[token]/page.tsx +200 -0
  52. package/template/src/app/(auth)/layout.tsx +3 -0
  53. package/template/src/app/(auth)/reset-password/complete/page.tsx +213 -0
  54. package/template/src/app/(auth)/reset-password/page.tsx +146 -0
  55. package/template/src/app/(auth)/reset-password/verify/page.tsx +183 -0
  56. package/template/src/app/(auth)/signin/page.tsx +166 -0
  57. package/template/src/app/(dashboard)/agenda/page.tsx +3051 -0
  58. package/template/src/app/(dashboard)/automatisation/[id]/page.tsx +24 -0
  59. package/template/src/app/(dashboard)/automatisation/_components/workflow-editor.tsx +905 -0
  60. package/template/src/app/(dashboard)/automatisation/new/page.tsx +20 -0
  61. package/template/src/app/(dashboard)/automatisation/page.tsx +337 -0
  62. package/template/src/app/(dashboard)/closing/page.tsx +1052 -0
  63. package/template/src/app/(dashboard)/contacts/[id]/page.tsx +6028 -0
  64. package/template/src/app/(dashboard)/contacts/page.tsx +3713 -0
  65. package/template/src/app/(dashboard)/dashboard/page.tsx +186 -0
  66. package/template/src/app/(dashboard)/layout.tsx +30 -0
  67. package/template/src/app/(dashboard)/settings/page.tsx +4070 -0
  68. package/template/src/app/(dashboard)/templates/page.tsx +567 -0
  69. package/template/src/app/(dashboard)/users/list/page.tsx +507 -0
  70. package/template/src/app/(dashboard)/users/page.tsx +457 -0
  71. package/template/src/app/(dashboard)/users/permissions/page.tsx +181 -0
  72. package/template/src/app/(dashboard)/users/roles/page.tsx +434 -0
  73. package/template/src/app/api/audit-logs/route.ts +57 -0
  74. package/template/src/app/api/auth/[...all]/route.ts +4 -0
  75. package/template/src/app/api/auth/check-active/route.ts +31 -0
  76. package/template/src/app/api/auth/google/callback/route.ts +94 -0
  77. package/template/src/app/api/auth/google/disconnect/route.ts +32 -0
  78. package/template/src/app/api/auth/google/route.ts +34 -0
  79. package/template/src/app/api/auth/google/status/route.ts +32 -0
  80. package/template/src/app/api/closing-reasons/route.ts +27 -0
  81. package/template/src/app/api/contacts/[id]/files/[fileId]/route.ts +94 -0
  82. package/template/src/app/api/contacts/[id]/files/route.ts +269 -0
  83. package/template/src/app/api/contacts/[id]/interactions/[interactionId]/route.ts +91 -0
  84. package/template/src/app/api/contacts/[id]/interactions/route.ts +103 -0
  85. package/template/src/app/api/contacts/[id]/meet/route.ts +296 -0
  86. package/template/src/app/api/contacts/[id]/route.ts +322 -0
  87. package/template/src/app/api/contacts/[id]/send-email/route.ts +254 -0
  88. package/template/src/app/api/contacts/export/route.ts +270 -0
  89. package/template/src/app/api/contacts/import/route.ts +381 -0
  90. package/template/src/app/api/contacts/route.ts +283 -0
  91. package/template/src/app/api/dashboard/stats/route.ts +299 -0
  92. package/template/src/app/api/email/track/[id]/route.ts +68 -0
  93. package/template/src/app/api/integrations/google-sheet/sync/route.ts +526 -0
  94. package/template/src/app/api/invite/complete/route.ts +88 -0
  95. package/template/src/app/api/invite/validate/route.ts +55 -0
  96. package/template/src/app/api/reminders/route.ts +95 -0
  97. package/template/src/app/api/reset-password/complete/route.ts +73 -0
  98. package/template/src/app/api/reset-password/request/route.ts +84 -0
  99. package/template/src/app/api/reset-password/validate/route.ts +49 -0
  100. package/template/src/app/api/reset-password/verify/route.ts +74 -0
  101. package/template/src/app/api/roles/[id]/route.ts +183 -0
  102. package/template/src/app/api/roles/route.ts +140 -0
  103. package/template/src/app/api/send/route.ts +282 -0
  104. package/template/src/app/api/settings/change-password/route.ts +95 -0
  105. package/template/src/app/api/settings/closing-reasons/[id]/route.ts +84 -0
  106. package/template/src/app/api/settings/closing-reasons/route.ts +74 -0
  107. package/template/src/app/api/settings/company/route.ts +121 -0
  108. package/template/src/app/api/settings/google-ads/[id]/route.ts +117 -0
  109. package/template/src/app/api/settings/google-ads/route.ts +122 -0
  110. package/template/src/app/api/settings/google-sheet/[id]/route.ts +230 -0
  111. package/template/src/app/api/settings/google-sheet/auto-map/route.ts +196 -0
  112. package/template/src/app/api/settings/google-sheet/route.ts +254 -0
  113. package/template/src/app/api/settings/meta-leads/[id]/route.ts +123 -0
  114. package/template/src/app/api/settings/meta-leads/route.ts +132 -0
  115. package/template/src/app/api/settings/profile/route.ts +42 -0
  116. package/template/src/app/api/settings/smtp/route.ts +130 -0
  117. package/template/src/app/api/settings/smtp/test/route.ts +121 -0
  118. package/template/src/app/api/settings/statuses/[id]/route.ts +101 -0
  119. package/template/src/app/api/settings/statuses/route.ts +83 -0
  120. package/template/src/app/api/statuses/route.ts +25 -0
  121. package/template/src/app/api/tasks/[id]/attendees/route.ts +76 -0
  122. package/template/src/app/api/tasks/[id]/route.ts +728 -0
  123. package/template/src/app/api/tasks/meet/route.ts +240 -0
  124. package/template/src/app/api/tasks/route.ts +417 -0
  125. package/template/src/app/api/templates/[id]/route.ts +140 -0
  126. package/template/src/app/api/templates/route.ts +91 -0
  127. package/template/src/app/api/users/[id]/route.ts +168 -0
  128. package/template/src/app/api/users/list/route.ts +45 -0
  129. package/template/src/app/api/users/me/route.ts +48 -0
  130. package/template/src/app/api/users/route.ts +250 -0
  131. package/template/src/app/api/webhooks/google-ads/route.ts +208 -0
  132. package/template/src/app/api/webhooks/meta-leads/route.ts +258 -0
  133. package/template/src/app/api/workflows/[id]/route.ts +192 -0
  134. package/template/src/app/api/workflows/process/route.ts +293 -0
  135. package/template/src/app/api/workflows/route.ts +124 -0
  136. package/template/src/app/favicon.ico +0 -0
  137. package/template/src/app/globals.css +1416 -0
  138. package/template/src/app/layout.tsx +31 -0
  139. package/template/src/app/page.tsx +32 -0
  140. package/template/src/components/dashboard/activity-chart.tsx +67 -0
  141. package/template/src/components/dashboard/contacts-chart.tsx +63 -0
  142. package/template/src/components/dashboard/recent-activity.tsx +164 -0
  143. package/template/src/components/dashboard/sales-analytics-chart.tsx +81 -0
  144. package/template/src/components/dashboard/stat-card.tsx +61 -0
  145. package/template/src/components/dashboard/status-distribution-chart.tsx +45 -0
  146. package/template/src/components/dashboard/tasks-pie-chart.tsx +88 -0
  147. package/template/src/components/dashboard/top-contacts-list.tsx +129 -0
  148. package/template/src/components/dashboard/upcoming-tasks-list.tsx +126 -0
  149. package/template/src/components/editor.tsx +856 -0
  150. package/template/src/components/email-template.tsx +35 -0
  151. package/template/src/components/header.tsx +320 -0
  152. package/template/src/components/invitation-email-template.tsx +79 -0
  153. package/template/src/components/meet-cancellation-email-template.tsx +120 -0
  154. package/template/src/components/meet-confirmation-email-template.tsx +156 -0
  155. package/template/src/components/meet-update-email-template.tsx +209 -0
  156. package/template/src/components/page-header.tsx +61 -0
  157. package/template/src/components/reset-password-email-template.tsx +79 -0
  158. package/template/src/components/sidebar.tsx +294 -0
  159. package/template/src/components/skeleton.tsx +380 -0
  160. package/template/src/components/ui/commands.tsx +396 -0
  161. package/template/src/components/ui/components.tsx +150 -0
  162. package/template/src/components/ui/theme.tsx +5 -0
  163. package/template/src/components/view-as-banner.tsx +45 -0
  164. package/template/src/components/view-as-modal.tsx +186 -0
  165. package/template/src/contexts/mobile-menu-context.tsx +31 -0
  166. package/template/src/contexts/sidebar-context.tsx +107 -0
  167. package/template/src/contexts/task-reminder-context.tsx +239 -0
  168. package/template/src/contexts/view-as-context.tsx +84 -0
  169. package/template/src/hooks/use-user-role.ts +82 -0
  170. package/template/src/lib/audit-log.ts +45 -0
  171. package/template/src/lib/auth-client.ts +16 -0
  172. package/template/src/lib/auth.ts +35 -0
  173. package/template/src/lib/check-permission.ts +193 -0
  174. package/template/src/lib/contact-duplicate.ts +112 -0
  175. package/template/src/lib/contact-interactions.ts +371 -0
  176. package/template/src/lib/encryption.ts +99 -0
  177. package/template/src/lib/google-calendar.ts +300 -0
  178. package/template/src/lib/google-drive.ts +372 -0
  179. package/template/src/lib/permissions.ts +412 -0
  180. package/template/src/lib/prisma.ts +32 -0
  181. package/template/src/lib/roles.ts +120 -0
  182. package/template/src/lib/template-variables.ts +76 -0
  183. package/template/src/lib/utils.ts +46 -0
  184. package/template/src/lib/workflow-executor.ts +482 -0
  185. package/template/src/proxy.ts +91 -0
  186. package/template/tsconfig.json +34 -0
  187. package/template/vercel.json +8 -0
@@ -0,0 +1,140 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+ import { auth } from '@/lib/auth';
3
+ import { prisma } from '@/lib/prisma';
4
+
5
+ // GET /api/templates/[id] - Récupérer un template spécifique
6
+ export async function GET(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
7
+ try {
8
+ const session = await auth.api.getSession({
9
+ headers: request.headers,
10
+ });
11
+
12
+ if (!session) {
13
+ return NextResponse.json({ error: 'Non authentifié' }, { status: 401 });
14
+ }
15
+
16
+ const { id } = await params;
17
+
18
+ const template = await prisma.template.findFirst({
19
+ where: {
20
+ id,
21
+ userId: session.user.id,
22
+ },
23
+ });
24
+
25
+ if (!template) {
26
+ return NextResponse.json({ error: 'Template non trouvé' }, { status: 404 });
27
+ }
28
+
29
+ return NextResponse.json(template);
30
+ } catch (error: any) {
31
+ console.error('Erreur lors de la récupération du template:', error);
32
+ return NextResponse.json({ error: 'Erreur serveur' }, { status: 500 });
33
+ }
34
+ }
35
+
36
+ // PUT /api/templates/[id] - Mettre à jour un template
37
+ export async function PUT(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
38
+ try {
39
+ const session = await auth.api.getSession({
40
+ headers: request.headers,
41
+ });
42
+
43
+ if (!session) {
44
+ return NextResponse.json({ error: 'Non authentifié' }, { status: 401 });
45
+ }
46
+
47
+ const { id } = await params;
48
+ const body = await request.json();
49
+ const { name, type, subject, content } = body;
50
+
51
+ // Vérifier que le template existe et appartient à l'utilisateur
52
+ const existing = await prisma.template.findFirst({
53
+ where: {
54
+ id,
55
+ userId: session.user.id,
56
+ },
57
+ });
58
+
59
+ if (!existing) {
60
+ return NextResponse.json({ error: 'Template non trouvé' }, { status: 404 });
61
+ }
62
+
63
+ // Validation
64
+ if (!name || !type || !content) {
65
+ return NextResponse.json(
66
+ { error: 'Le nom, le type et le contenu sont requis' },
67
+ { status: 400 },
68
+ );
69
+ }
70
+
71
+ if (!['EMAIL', 'SMS', 'NOTE'].includes(type)) {
72
+ return NextResponse.json(
73
+ { error: 'Type invalide. Doit être EMAIL, SMS ou NOTE' },
74
+ { status: 400 },
75
+ );
76
+ }
77
+
78
+ // Pour EMAIL, le sujet est requis
79
+ if (type === 'EMAIL' && !subject) {
80
+ return NextResponse.json(
81
+ { error: 'Le sujet est requis pour les templates EMAIL' },
82
+ { status: 400 },
83
+ );
84
+ }
85
+
86
+ const template = await prisma.template.update({
87
+ where: { id },
88
+ data: {
89
+ name,
90
+ type,
91
+ subject: type === 'EMAIL' ? subject : null,
92
+ content,
93
+ },
94
+ });
95
+
96
+ return NextResponse.json(template);
97
+ } catch (error: any) {
98
+ console.error('Erreur lors de la mise à jour du template:', error);
99
+ return NextResponse.json({ error: error.message || 'Erreur serveur' }, { status: 500 });
100
+ }
101
+ }
102
+
103
+ // DELETE /api/templates/[id] - Supprimer un template
104
+ export async function DELETE(
105
+ request: NextRequest,
106
+ { params }: { params: Promise<{ id: string }> },
107
+ ) {
108
+ try {
109
+ const session = await auth.api.getSession({
110
+ headers: request.headers,
111
+ });
112
+
113
+ if (!session) {
114
+ return NextResponse.json({ error: 'Non authentifié' }, { status: 401 });
115
+ }
116
+
117
+ const { id } = await params;
118
+
119
+ // Vérifier que le template existe et appartient à l'utilisateur
120
+ const existing = await prisma.template.findFirst({
121
+ where: {
122
+ id,
123
+ userId: session.user.id,
124
+ },
125
+ });
126
+
127
+ if (!existing) {
128
+ return NextResponse.json({ error: 'Template non trouvé' }, { status: 404 });
129
+ }
130
+
131
+ await prisma.template.delete({
132
+ where: { id },
133
+ });
134
+
135
+ return NextResponse.json({ success: true, message: 'Template supprimé avec succès' });
136
+ } catch (error: any) {
137
+ console.error('Erreur lors de la suppression du template:', error);
138
+ return NextResponse.json({ error: error.message || 'Erreur serveur' }, { status: 500 });
139
+ }
140
+ }
@@ -0,0 +1,91 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+ import { auth } from '@/lib/auth';
3
+ import { prisma } from '@/lib/prisma';
4
+
5
+ // GET /api/templates - Récupérer tous les templates de l'utilisateur
6
+ export async function GET(request: NextRequest) {
7
+ try {
8
+ const session = await auth.api.getSession({
9
+ headers: request.headers,
10
+ });
11
+
12
+ if (!session) {
13
+ return NextResponse.json({ error: 'Non authentifié' }, { status: 401 });
14
+ }
15
+
16
+ const { searchParams } = new URL(request.url);
17
+ const type = searchParams.get('type'); // EMAIL, SMS, NOTE
18
+
19
+ const where: any = {
20
+ userId: session.user.id,
21
+ };
22
+
23
+ if (type) {
24
+ where.type = type;
25
+ }
26
+
27
+ const templates = await prisma.template.findMany({
28
+ where,
29
+ orderBy: { updatedAt: 'desc' },
30
+ });
31
+
32
+ return NextResponse.json(templates);
33
+ } catch (error: any) {
34
+ console.error('Erreur lors de la récupération des templates:', error);
35
+ return NextResponse.json({ error: 'Erreur serveur' }, { status: 500 });
36
+ }
37
+ }
38
+
39
+ // POST /api/templates - Créer un nouveau template
40
+ export async function POST(request: NextRequest) {
41
+ try {
42
+ const session = await auth.api.getSession({
43
+ headers: request.headers,
44
+ });
45
+
46
+ if (!session) {
47
+ return NextResponse.json({ error: 'Non authentifié' }, { status: 401 });
48
+ }
49
+
50
+ const body = await request.json();
51
+ const { name, type, subject, content } = body;
52
+
53
+ // Validation
54
+ if (!name || !type || !content) {
55
+ return NextResponse.json(
56
+ { error: 'Le nom, le type et le contenu sont requis' },
57
+ { status: 400 },
58
+ );
59
+ }
60
+
61
+ if (!['EMAIL', 'SMS', 'NOTE'].includes(type)) {
62
+ return NextResponse.json(
63
+ { error: 'Type invalide. Doit être EMAIL, SMS ou NOTE' },
64
+ { status: 400 },
65
+ );
66
+ }
67
+
68
+ // Pour EMAIL, le sujet est requis
69
+ if (type === 'EMAIL' && !subject) {
70
+ return NextResponse.json(
71
+ { error: 'Le sujet est requis pour les templates EMAIL' },
72
+ { status: 400 },
73
+ );
74
+ }
75
+
76
+ const template = await prisma.template.create({
77
+ data: {
78
+ name,
79
+ type,
80
+ subject: type === 'EMAIL' ? subject : null,
81
+ content,
82
+ userId: session.user.id,
83
+ },
84
+ });
85
+
86
+ return NextResponse.json(template, { status: 201 });
87
+ } catch (error: any) {
88
+ console.error('Erreur lors de la création du template:', error);
89
+ return NextResponse.json({ error: error.message || 'Erreur serveur' }, { status: 500 });
90
+ }
91
+ }
@@ -0,0 +1,168 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+ import { prisma } from '@/lib/prisma';
3
+ import { checkPermission } from '@/lib/check-permission';
4
+ import { auth } from '@/lib/auth';
5
+ import { logAudit } from '@/lib/audit-log';
6
+
7
+ // GET /api/users/[id] - Récupérer un utilisateur spécifique
8
+ export async function GET(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
9
+ try {
10
+ const session = await auth.api.getSession({
11
+ headers: request.headers,
12
+ });
13
+
14
+ if (!session) {
15
+ return NextResponse.json({ error: 'Non authentifié' }, { status: 401 });
16
+ }
17
+
18
+ // Vérifier que l'utilisateur a la permission de voir les utilisateurs
19
+ const hasPermission = await checkPermission('users.view');
20
+ if (!hasPermission) {
21
+ return NextResponse.json({ error: 'Accès refusé' }, { status: 403 });
22
+ }
23
+ const { id } = await params;
24
+
25
+ const user = await prisma.user.findUnique({
26
+ where: { id },
27
+ });
28
+
29
+ if (!user) {
30
+ return NextResponse.json({ error: 'Utilisateur non trouvé' }, { status: 404 });
31
+ }
32
+
33
+ // Retourner l'utilisateur avec le rôle
34
+ return NextResponse.json({
35
+ id: user.id,
36
+ name: user.name,
37
+ email: user.email,
38
+ role: user.role || 'USER',
39
+ emailVerified: user.emailVerified,
40
+ active: user.active,
41
+ image: user.image,
42
+ createdAt: user.createdAt,
43
+ updatedAt: user.updatedAt,
44
+ });
45
+ } catch (error: any) {
46
+ console.error('Erreur:', error);
47
+
48
+ if (error.message === 'Non authentifié') {
49
+ return NextResponse.json({ error: 'Non authentifié' }, { status: 401 });
50
+ }
51
+
52
+ if (error.message === 'Permissions insuffisantes') {
53
+ return NextResponse.json({ error: 'Accès refusé' }, { status: 403 });
54
+ }
55
+
56
+ return NextResponse.json({ error: 'Erreur serveur' }, { status: 500 });
57
+ }
58
+ }
59
+
60
+ // PUT /api/users/[id] - Mettre à jour un utilisateur
61
+ export async function PUT(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
62
+ try {
63
+ const session = await auth.api.getSession({
64
+ headers: request.headers,
65
+ });
66
+
67
+ if (!session) {
68
+ return NextResponse.json({ error: 'Non authentifié' }, { status: 401 });
69
+ }
70
+
71
+ // Vérifier que l'utilisateur a la permission de modifier des utilisateurs
72
+ const hasPermission = await checkPermission('users.edit');
73
+ if (!hasPermission) {
74
+ return NextResponse.json({ error: 'Accès refusé' }, { status: 403 });
75
+ }
76
+ const { id } = await params;
77
+ const body = await request.json();
78
+ const { name, customRoleId, active } = body;
79
+
80
+ // Vérifier que l'utilisateur existe
81
+ const existingUser = await prisma.user.findUnique({
82
+ where: { id },
83
+ });
84
+
85
+ if (!existingUser) {
86
+ return NextResponse.json({ error: 'Utilisateur non trouvé' }, { status: 404 });
87
+ }
88
+
89
+ // Mettre à jour l'utilisateur
90
+ const updatedUser = await prisma.user.update({
91
+ where: { id },
92
+ data: {
93
+ ...(name && { name }),
94
+ ...(customRoleId !== undefined && { customRoleId: customRoleId || null }),
95
+ ...(typeof active === 'boolean' && { active }),
96
+ },
97
+ include: {
98
+ customRole: {
99
+ select: {
100
+ id: true,
101
+ name: true,
102
+ },
103
+ },
104
+ },
105
+ });
106
+
107
+ // Récupérer les noms des profils pour les métadonnées
108
+ const getRoleName = async (roleId: string | null) => {
109
+ if (!roleId) return null;
110
+ const role = await prisma.customRole.findUnique({
111
+ where: { id: roleId },
112
+ select: { name: true },
113
+ });
114
+ return role?.name || null;
115
+ };
116
+
117
+ // Log d'audit : modification utilisateur
118
+ const changes: Record<string, { old: any; new: any }> = {};
119
+ if (name && name !== existingUser.name) {
120
+ changes.name = { old: existingUser.name, new: name };
121
+ }
122
+ if (customRoleId !== undefined && customRoleId !== existingUser.customRoleId) {
123
+ const oldRoleName = await getRoleName(existingUser.customRoleId);
124
+ const newRoleName = await getRoleName(customRoleId || null);
125
+ changes.profil = {
126
+ old: oldRoleName || 'Aucun',
127
+ new: newRoleName || 'Aucun',
128
+ };
129
+ }
130
+ if (typeof active === 'boolean' && active !== existingUser.active) {
131
+ changes.active = {
132
+ old: existingUser.active ? 'Actif' : 'Inactif',
133
+ new: active ? 'Actif' : 'Inactif',
134
+ };
135
+ }
136
+
137
+ if (Object.keys(changes).length > 0) {
138
+ await logAudit({
139
+ actorId: session.user.id,
140
+ targetUserId: updatedUser.id,
141
+ action: 'USER_UPDATED',
142
+ entityType: 'USER',
143
+ entityId: updatedUser.id,
144
+ metadata: {
145
+ changes,
146
+ },
147
+ });
148
+ }
149
+
150
+ // Retourner l'utilisateur avec le profil
151
+ return NextResponse.json({
152
+ id: updatedUser.id,
153
+ name: updatedUser.name,
154
+ email: updatedUser.email,
155
+ role: updatedUser.role || 'USER',
156
+ customRoleId: updatedUser.customRoleId,
157
+ customRole: updatedUser.customRole,
158
+ emailVerified: updatedUser.emailVerified,
159
+ active: updatedUser.active,
160
+ updatedAt: updatedUser.updatedAt,
161
+ });
162
+ } catch (error: any) {
163
+ console.error('Erreur:', error);
164
+ return NextResponse.json({ error: 'Erreur serveur' }, { status: 500 });
165
+ }
166
+ }
167
+
168
+ // NOTE: L'API DELETE n'est plus utilisée : les comptes sont désormais désactivés via le booléen `active`.
@@ -0,0 +1,45 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+ import { auth } from '@/lib/auth';
3
+ import { prisma } from '@/lib/prisma';
4
+ import { checkPermission } from '@/lib/check-permission';
5
+
6
+ // GET /api/users/list - Récupérer la liste des utilisateurs avec leurs profils (pour les admins)
7
+ export async function GET(request: NextRequest) {
8
+ try {
9
+ const session = await auth.api.getSession({
10
+ headers: request.headers,
11
+ });
12
+
13
+ if (!session) {
14
+ return NextResponse.json({ error: 'Non authentifié' }, { status: 401 });
15
+ }
16
+
17
+ // Vérifier que l'utilisateur a la permission de gérer les rôles (admin)
18
+ const hasPermission = await checkPermission('users.manage_roles');
19
+ if (!hasPermission) {
20
+ return NextResponse.json({ error: 'Accès refusé' }, { status: 403 });
21
+ }
22
+
23
+ // Récupérer tous les utilisateurs avec leurs profils
24
+ const users = await prisma.user.findMany({
25
+ select: {
26
+ id: true,
27
+ name: true,
28
+ email: true,
29
+ customRole: {
30
+ select: {
31
+ id: true,
32
+ name: true,
33
+ permissions: true,
34
+ },
35
+ },
36
+ },
37
+ orderBy: { name: 'asc' },
38
+ });
39
+
40
+ return NextResponse.json(users);
41
+ } catch (error: any) {
42
+ console.error('Erreur lors de la récupération des utilisateurs:', error);
43
+ return NextResponse.json({ error: 'Erreur serveur' }, { status: 500 });
44
+ }
45
+ }
@@ -0,0 +1,48 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+ import { auth } from '@/lib/auth';
3
+ import { prisma } from '@/lib/prisma';
4
+
5
+ // GET /api/users/me - Récupérer les informations de l'utilisateur actuel (y compris le rôle)
6
+ export async function GET(request: NextRequest) {
7
+ try {
8
+ const session = await auth.api.getSession({
9
+ headers: request.headers,
10
+ });
11
+
12
+ if (!session) {
13
+ return NextResponse.json({ error: 'Non authentifié' }, { status: 401 });
14
+ }
15
+
16
+ // Récupérer l'utilisateur avec son profil depuis la base de données
17
+ const user = await prisma.user.findUnique({
18
+ where: { id: session.user.id },
19
+ include: {
20
+ customRole: {
21
+ select: {
22
+ id: true,
23
+ name: true,
24
+ permissions: true,
25
+ },
26
+ },
27
+ },
28
+ });
29
+
30
+ if (!user) {
31
+ return NextResponse.json({ error: 'Utilisateur non trouvé' }, { status: 404 });
32
+ }
33
+
34
+ // Retourner l'utilisateur avec son profil et ses permissions
35
+ return NextResponse.json({
36
+ id: user.id,
37
+ name: user.name,
38
+ email: user.email,
39
+ role: 'USER', // Tous les utilisateurs ont le rôle USER
40
+ customRole: user.customRole,
41
+ emailVerified: user.emailVerified,
42
+ image: user.image,
43
+ });
44
+ } catch (error) {
45
+ console.error('Erreur:', error);
46
+ return NextResponse.json({ error: 'Erreur serveur' }, { status: 500 });
47
+ }
48
+ }