create-crm-tmp 1.1.3 → 2.1.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.
- package/bin/create-crm-tmp.js +56 -35
- package/package.json +1 -1
- package/template/.prettierignore +2 -0
- package/template/README.md +230 -115
- package/template/components.json +22 -0
- package/template/eslint.config.mjs +13 -0
- package/template/exemple-contacts.csv +54 -0
- package/template/next.config.ts +41 -1
- package/template/package.json +63 -15
- package/template/prisma/migrations/20260318095700_init_db/migration.sql +978 -0
- package/template/prisma/schema.prisma +311 -67
- package/template/src/app/(auth)/invite/[token]/page.tsx +28 -29
- package/template/src/app/(auth)/layout.tsx +1 -1
- package/template/src/app/(auth)/reset-password/complete/page.tsx +21 -27
- package/template/src/app/(auth)/reset-password/page.tsx +14 -10
- package/template/src/app/(auth)/reset-password/verify/page.tsx +14 -10
- package/template/src/app/(auth)/signin/page.tsx +34 -23
- package/template/src/app/(dashboard)/agenda/page.tsx +3655 -2357
- package/template/src/app/(dashboard)/automatisation/[id]/page.tsx +10 -7
- package/template/src/app/(dashboard)/automatisation/_components/workflow-editor.tsx +609 -338
- package/template/src/app/(dashboard)/automatisation/new/page.tsx +11 -8
- package/template/src/app/(dashboard)/automatisation/page.tsx +463 -186
- package/template/src/app/(dashboard)/closing/page.tsx +517 -469
- package/template/src/app/(dashboard)/contacts/[id]/page.tsx +6151 -4210
- package/template/src/app/(dashboard)/contacts/companies/[id]/page.tsx +1702 -0
- package/template/src/app/(dashboard)/contacts/loading.tsx +13 -0
- package/template/src/app/(dashboard)/contacts/page.tsx +4124 -2130
- package/template/src/app/(dashboard)/dashboard/page.tsx +119 -105
- package/template/src/app/(dashboard)/dev/page.tsx +1291 -0
- package/template/src/app/(dashboard)/error.tsx +37 -0
- package/template/src/app/(dashboard)/layout.tsx +6 -2
- package/template/src/app/(dashboard)/loading.tsx +5 -0
- package/template/src/app/(dashboard)/settings/loading.tsx +19 -0
- package/template/src/app/(dashboard)/settings/page.tsx +1773 -3362
- package/template/src/app/(dashboard)/templates/page.tsx +504 -303
- package/template/src/app/(dashboard)/users/list/page.tsx +364 -355
- package/template/src/app/(dashboard)/users/page.tsx +279 -310
- package/template/src/app/(dashboard)/users/permissions/page.tsx +104 -99
- package/template/src/app/(dashboard)/users/roles/page.tsx +169 -140
- package/template/src/app/api/agenda/google-events/route.ts +92 -0
- package/template/src/app/api/audit-logs/route.ts +1 -1
- package/template/src/app/api/auth/check-active/route.ts +3 -2
- package/template/src/app/api/auth/google/callback/route.ts +8 -5
- package/template/src/app/api/auth/google/disconnect/route.ts +2 -2
- package/template/src/app/api/auth/google/route.ts +2 -1
- package/template/src/app/api/auth/google/status/route.ts +7 -31
- package/template/src/app/api/companies/[id]/activities/route.ts +129 -0
- package/template/src/app/api/companies/[id]/route.ts +194 -0
- package/template/src/app/api/companies/export/route.ts +206 -0
- package/template/src/app/api/companies/route.ts +196 -0
- package/template/src/app/api/contact-views/[id]/pin/route.ts +69 -0
- package/template/src/app/api/contact-views/[id]/route.ts +197 -0
- package/template/src/app/api/contact-views/route.ts +146 -0
- package/template/src/app/api/contacts/[id]/files/[fileId]/preview/route.ts +55 -0
- package/template/src/app/api/contacts/[id]/files/[fileId]/route.ts +20 -48
- package/template/src/app/api/contacts/[id]/files/route.ts +125 -186
- package/template/src/app/api/contacts/[id]/interactions/[interactionId]/route.ts +27 -1
- package/template/src/app/api/contacts/[id]/interactions/route.ts +45 -8
- package/template/src/app/api/contacts/[id]/kyc/route.ts +81 -0
- package/template/src/app/api/contacts/[id]/meet/route.ts +55 -29
- package/template/src/app/api/contacts/[id]/route.ts +184 -21
- package/template/src/app/api/contacts/[id]/send-email/route.ts +33 -11
- package/template/src/app/api/contacts/[id]/workflows/run/route.ts +67 -0
- package/template/src/app/api/contacts/export/route.ts +22 -31
- package/template/src/app/api/contacts/import/route.ts +77 -44
- package/template/src/app/api/contacts/import-preview/route.ts +139 -0
- package/template/src/app/api/contacts/origins/route.ts +63 -0
- package/template/src/app/api/contacts/route.ts +322 -57
- package/template/src/app/api/cron/cleanup-editor-images/route.ts +166 -0
- package/template/src/app/api/dashboard/stats/route.ts +9 -292
- package/template/src/app/api/dashboard/widgets/[id]/route.ts +0 -3
- package/template/src/app/api/dashboard/widgets/route.ts +19 -19
- package/template/src/app/api/dev/reminders/test/route.ts +114 -0
- package/template/src/app/api/editor/upload-image/route.ts +61 -0
- package/template/src/app/api/integrations/google-sheet/jobs/[jobId]/route.ts +47 -0
- package/template/src/app/api/integrations/google-sheet/jobs/usage/route.ts +50 -0
- package/template/src/app/api/integrations/google-sheet/sync/route.ts +28 -542
- package/template/src/app/api/invite/complete/route.ts +20 -23
- package/template/src/app/api/jobs/google-sheet/process/route.ts +84 -0
- package/template/src/app/api/jobs/google-sheet/schedule/route.ts +50 -0
- package/template/src/app/api/reminders/clear/route.ts +120 -0
- package/template/src/app/api/reminders/clear/undo/route.ts +112 -0
- package/template/src/app/api/reminders/route.ts +165 -39
- package/template/src/app/api/reminders/state/route.ts +164 -0
- package/template/src/app/api/reset-password/complete/route.ts +11 -13
- package/template/src/app/api/reset-password/request/route.ts +1 -1
- package/template/src/app/api/reset-password/verify/route.ts +1 -1
- package/template/src/app/api/send/route.ts +25 -47
- package/template/src/app/api/settings/closing-reasons/[id]/route.ts +10 -21
- package/template/src/app/api/settings/closing-reasons/route.ts +10 -21
- package/template/src/app/api/settings/company/route.ts +19 -26
- package/template/src/app/api/settings/google-ads/[id]/route.ts +20 -23
- package/template/src/app/api/settings/google-ads/route.ts +34 -23
- package/template/src/app/api/settings/google-calendar/calendars/route.ts +97 -0
- package/template/src/app/api/settings/google-calendar/route.ts +124 -0
- package/template/src/app/api/settings/google-sheet/[id]/route.ts +48 -23
- package/template/src/app/api/settings/google-sheet/auto-map/route.ts +56 -32
- package/template/src/app/api/settings/google-sheet/preview/route.ts +110 -0
- package/template/src/app/api/settings/google-sheet/route.ts +34 -23
- package/template/src/app/api/settings/integrations/logs/route.ts +93 -0
- package/template/src/app/api/settings/integrations/notifications/route.ts +67 -0
- package/template/src/app/api/settings/meta-leads/[id]/route.ts +20 -24
- package/template/src/app/api/settings/meta-leads/route.ts +34 -25
- package/template/src/app/api/settings/smtp/route.ts +53 -6
- package/template/src/app/api/settings/statuses/[id]/route.ts +29 -32
- package/template/src/app/api/settings/statuses/route.ts +24 -22
- package/template/src/app/api/statuses/route.ts +2 -5
- package/template/src/app/api/tasks/[id]/attendees/route.ts +36 -13
- package/template/src/app/api/tasks/[id]/route.ts +357 -145
- package/template/src/app/api/tasks/meet/route.ts +37 -26
- package/template/src/app/api/tasks/route.ts +201 -96
- package/template/src/app/api/templates/[id]/route.ts +22 -13
- package/template/src/app/api/templates/route.ts +22 -5
- package/template/src/app/api/users/[id]/resend-invite/route.ts +95 -0
- package/template/src/app/api/users/[id]/route.ts +22 -16
- package/template/src/app/api/users/commercials/route.ts +38 -0
- package/template/src/app/api/users/for-agenda/route.ts +1 -2
- package/template/src/app/api/users/list/route.ts +57 -19
- package/template/src/app/api/users/route.ts +89 -34
- package/template/src/app/api/webhooks/google-ads/route.ts +40 -1
- package/template/src/app/api/webhooks/meta-leads/route.ts +38 -1
- package/template/src/app/api/workflows/[id]/route.ts +29 -6
- package/template/src/app/api/workflows/process/route.ts +505 -170
- package/template/src/app/api/workflows/route.ts +42 -4
- package/template/src/app/globals.css +512 -32
- package/template/src/app/layout.tsx +28 -9
- package/template/src/app/page.tsx +37 -7
- package/template/src/components/address-autocomplete.tsx +233 -0
- package/template/src/components/config-error-alert.tsx +46 -0
- package/template/src/components/contacts/filter-bar.tsx +190 -0
- package/template/src/components/contacts/filter-builder.tsx +574 -0
- package/template/src/components/contacts/save-view-dialog.tsx +160 -0
- package/template/src/components/contacts/views-tab-bar.tsx +449 -0
- package/template/src/components/dashboard/activity-chart.tsx +6 -1
- package/template/src/components/dashboard/add-widget-dialog.tsx +13 -17
- package/template/src/components/dashboard/color-picker.tsx +7 -8
- package/template/src/components/dashboard/recent-activity.tsx +2 -5
- package/template/src/components/dashboard/stat-card.tsx +1 -3
- package/template/src/components/dashboard/status-distribution-chart.tsx +0 -1
- package/template/src/components/dashboard/top-contacts-list.tsx +7 -13
- package/template/src/components/dashboard/upcoming-tasks-list.tsx +2 -5
- package/template/src/components/dashboard/widget-wrapper.tsx +3 -6
- package/template/src/components/date-picker.tsx +399 -0
- package/template/src/components/editor/upload-editor-image.ts +42 -0
- package/template/src/components/editor.tsx +188 -35
- package/template/src/components/email-template.tsx +4 -2
- package/template/src/components/global-search.tsx +360 -0
- package/template/src/components/header.tsx +200 -107
- package/template/src/components/inactive-account-guard.tsx +58 -0
- package/template/src/components/integration-notifications-listener.tsx +12 -0
- package/template/src/components/invitation-email-template.tsx +4 -2
- package/template/src/components/lazy-editor.tsx +11 -0
- package/template/src/components/meet-cancellation-email-template.tsx +11 -3
- package/template/src/components/meet-confirmation-email-template.tsx +10 -3
- package/template/src/components/meet-update-email-template.tsx +10 -3
- package/template/src/components/page-header.tsx +19 -15
- package/template/src/components/protected-page.tsx +94 -0
- package/template/src/components/reset-password-email-template.tsx +4 -2
- package/template/src/components/settings/integrations/GoogleAdsIntegration.tsx +428 -0
- package/template/src/components/settings/integrations/GoogleSheetConfigMonitoringModal.tsx +680 -0
- package/template/src/components/settings/integrations/GoogleSheetIntegration.tsx +809 -0
- package/template/src/components/settings/integrations/ImportResultDialog.tsx +124 -0
- package/template/src/components/settings/integrations/IntegrationLogPanel.tsx +57 -0
- package/template/src/components/settings/integrations/IntegrationLogsTable.tsx +186 -0
- package/template/src/components/settings/integrations/MetaLeadIntegration.tsx +451 -0
- package/template/src/components/sidebar.tsx +117 -100
- package/template/src/components/skeleton.tsx +128 -45
- package/template/src/components/ui/accordion.tsx +64 -0
- package/template/src/components/ui/alert-dialog.tsx +139 -0
- package/template/src/components/ui/button.tsx +71 -0
- package/template/src/components/ui/components.tsx +1 -1
- package/template/src/components/ui/date-picker.tsx +422 -0
- package/template/src/components/ui/datetime-picker.tsx +338 -0
- package/template/src/components/ui/status-select.tsx +271 -0
- package/template/src/components/ui/tooltip.tsx +37 -0
- package/template/src/components/view-as-banner.tsx +1 -1
- package/template/src/components/view-as-modal.tsx +30 -19
- package/template/src/config/nav-pages.ts +108 -0
- package/template/src/contexts/app-toast-context.tsx +362 -0
- package/template/src/contexts/dashboard-theme-context.tsx +2 -7
- package/template/src/contexts/sidebar-context.tsx +27 -53
- package/template/src/contexts/task-reminder-context.tsx +134 -160
- package/template/src/contexts/view-as-context.tsx +32 -10
- package/template/src/hooks/use-alert.tsx +65 -0
- package/template/src/hooks/use-confirm.tsx +87 -0
- package/template/src/hooks/use-contact-views.ts +140 -0
- package/template/src/hooks/use-contacts.ts +69 -0
- package/template/src/hooks/use-fetch.ts +17 -0
- package/template/src/hooks/use-focus-trap.ts +73 -0
- package/template/src/hooks/use-statuses.ts +22 -0
- package/template/src/hooks/useIntegrationNotifications.ts +49 -0
- package/template/src/lib/address-api.ts +155 -0
- package/template/src/lib/auth.ts +8 -1
- package/template/src/lib/cache.ts +73 -0
- package/template/src/lib/check-permission.ts +12 -177
- package/template/src/lib/config-links.ts +14 -0
- package/template/src/lib/contact-duplicate.ts +79 -61
- package/template/src/lib/contact-interactions.ts +24 -22
- package/template/src/lib/contact-view-filters.ts +301 -0
- package/template/src/lib/contacts-list-url.ts +190 -0
- package/template/src/lib/dashboard-stats.ts +282 -0
- package/template/src/lib/dashboard-themes.ts +0 -5
- package/template/src/lib/date-utils.ts +176 -0
- package/template/src/lib/default-widgets.ts +0 -2
- package/template/src/lib/editor-html-image-dimensions.ts +172 -0
- package/template/src/lib/editor-image-limits.ts +19 -0
- package/template/src/lib/email-html-sanitize.ts +19 -0
- package/template/src/lib/encryption.ts +9 -6
- package/template/src/lib/fr-geography.ts +192 -0
- package/template/src/lib/get-auth-user.ts +25 -0
- package/template/src/lib/google-calendar-agenda.ts +201 -0
- package/template/src/lib/google-calendar.ts +309 -17
- package/template/src/lib/google-fetch.ts +63 -0
- package/template/src/lib/google-sheet-sync-jobs.ts +96 -0
- package/template/src/lib/google-sheet-sync-runner.ts +514 -0
- package/template/src/lib/integration-import-log.ts +21 -0
- package/template/src/lib/local-storage.ts +34 -0
- package/template/src/lib/permissions.ts +268 -40
- package/template/src/lib/prisma.ts +15 -12
- package/template/src/lib/qstash.ts +65 -0
- package/template/src/lib/reminder-state-server.ts +80 -0
- package/template/src/lib/reminder-state.ts +29 -0
- package/template/src/lib/roles.ts +12 -15
- package/template/src/lib/supabase-storage.ts +113 -0
- package/template/src/lib/template-variables.ts +204 -29
- package/template/src/lib/utils.ts +71 -11
- package/template/src/lib/widget-registry.ts +0 -4
- package/template/src/lib/workflow-executor.ts +391 -228
- package/template/src/proxy.ts +35 -73
- package/template/src/types/contact-views.ts +351 -0
- package/template/vercel.json +5 -0
- package/template/WORKFLOWS_CRON.md +0 -185
- package/template/prisma/migrations/20251126144728_init/migration.sql +0 -78
- package/template/prisma/migrations/20251126155204_add_user_roles/migration.sql +0 -5
- package/template/prisma/migrations/20251128095126_add_company_info/migration.sql +0 -19
- package/template/prisma/migrations/20251128123321_add_smtp_config/migration.sql +0 -22
- package/template/prisma/migrations/20251128132303_add_status/migration.sql +0 -23
- package/template/prisma/migrations/20251201102207_add_user_active/migration.sql +0 -75
- package/template/prisma/migrations/20251201105507_add_email_signature/migration.sql +0 -2
- package/template/prisma/migrations/20251201151122_add_tasks/migration.sql +0 -45
- package/template/prisma/migrations/20251202111854_add_task_reminder/migration.sql +0 -2
- package/template/prisma/migrations/20251202135859_add_google_meet_integration/migration.sql +0 -27
- package/template/prisma/migrations/20251203103317_add_meta_lead_integration/migration.sql +0 -20
- package/template/prisma/migrations/20251203104002_add_google_ads_integration/migration.sql +0 -18
- package/template/prisma/migrations/20251203112122_add_google_sheet_integration/migration.sql +0 -32
- package/template/prisma/migrations/20251203153853_allow_multiple_integration_configs/migration.sql +0 -20
- package/template/prisma/migrations/20251205141705_update_user_roles/migration.sql +0 -12
- package/template/prisma/migrations/20251205150000_add_commercial_and_telepro_assignment/migration.sql +0 -21
- package/template/prisma/migrations/20251205160000_add_interaction_logging/migration.sql +0 -11
- package/template/prisma/migrations/20251208090314_add_automatic_interaction_types/migration.sql +0 -12
- package/template/prisma/migrations/20251208094843_mg/migration.sql +0 -14
- package/template/prisma/migrations/20251208100000_add_company_support/migration.sql +0 -14
- package/template/prisma/migrations/20251208110000_add_templates/migration.sql +0 -26
- package/template/prisma/migrations/20251208141304_add_video_conference_task_type/migration.sql +0 -2
- package/template/prisma/migrations/20251209104759_add_internal_note_to_task/migration.sql +0 -2
- package/template/prisma/migrations/20251209134803_add_company_field/migration.sql +0 -2
- package/template/prisma/migrations/20251209150000_rename_company_to_company_name/migration.sql +0 -3
- package/template/prisma/migrations/20251209150016_add_email_tracking/migration.sql +0 -21
- package/template/prisma/migrations/20251209155908_add_notify_contact_to_task/migration.sql +0 -2
- package/template/prisma/migrations/20251210110019_add_appointment_types/migration.sql +0 -10
- package/template/prisma/migrations/20251210113928_add_contact_files/migration.sql +0 -26
- package/template/prisma/migrations/20251212132339_add_custom_roles/migration.sql +0 -24
- package/template/prisma/migrations/20251215104448_add_file_interaction_types/migration.sql +0 -11
- package/template/prisma/migrations/20251215145616_add_closing_reasons/migration.sql +0 -12
- package/template/prisma/migrations/20251216140850_add_log_users/migration.sql +0 -25
- package/template/prisma/migrations/20251216151000_rename_perdu_to_ferme/migration.sql +0 -8
- package/template/prisma/migrations/20251216162318_add_column_mappings_to_google_sheet/migration.sql +0 -2
- package/template/prisma/migrations/20251216185127_add_workflows/migration.sql +0 -80
- package/template/prisma/migrations/20251216192237_add_scheduled_workflow_actions/migration.sql +0 -32
- package/template/prisma/migrations/20251220000000_add_task_interaction_type/migration.sql +0 -4
- package/template/prisma/migrations/20251221000000_add_task_type/migration.sql +0 -3
- package/template/prisma/migrations/20251221000001_add_event_color/migration.sql +0 -23
- package/template/prisma/migrations/20260210114913_add_dashboard_widget/migration.sql +0 -20
- package/template/prisma/migrations/20260226093949_fix_cascade_on_user_delete/migration.sql +0 -69
- package/template/src/app/(dashboard)/users/layout.tsx +0 -30
- package/template/src/lib/google-drive.ts +0 -380
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { auth } from '@/lib/auth';
|
|
3
|
+
import { prisma } from '@/lib/prisma';
|
|
4
|
+
import { REMINDERS_CLEAR_ALL_ID } from '@/lib/reminder-state';
|
|
5
|
+
import {
|
|
6
|
+
computeExpiresAtForUpsert,
|
|
7
|
+
getRequestId,
|
|
8
|
+
isMissingReminderStateTableError,
|
|
9
|
+
logReminderEvent,
|
|
10
|
+
reminderStateNotExpired,
|
|
11
|
+
} from '@/lib/reminder-state-server';
|
|
12
|
+
|
|
13
|
+
export async function GET(request: NextRequest) {
|
|
14
|
+
const started = Date.now();
|
|
15
|
+
const requestId = getRequestId(request);
|
|
16
|
+
let degraded = false;
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const session = await auth.api.getSession({ headers: request.headers });
|
|
20
|
+
if (!session) {
|
|
21
|
+
return NextResponse.json({ error: 'Non authentifié' }, { status: 401 });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const now = new Date();
|
|
25
|
+
let states: Array<{ reminderId: string; status: string; updatedAt: Date }> = [];
|
|
26
|
+
let clearAllState: { status: string; updatedAt: Date; clearedCutoffAt: Date | null } | undefined;
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const rows = await prisma.userReminderState.findMany({
|
|
30
|
+
where: {
|
|
31
|
+
userId: session.user.id,
|
|
32
|
+
AND: [reminderStateNotExpired(now)],
|
|
33
|
+
},
|
|
34
|
+
select: {
|
|
35
|
+
reminderId: true,
|
|
36
|
+
status: true,
|
|
37
|
+
updatedAt: true,
|
|
38
|
+
clearedCutoffAt: true,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
states = rows;
|
|
42
|
+
clearAllState = rows.find((state) => state.reminderId === REMINDERS_CLEAR_ALL_ID);
|
|
43
|
+
} catch (err) {
|
|
44
|
+
if (isMissingReminderStateTableError(err)) {
|
|
45
|
+
degraded = true;
|
|
46
|
+
logReminderEvent({
|
|
47
|
+
event: 'reminders_fallback_missing_table',
|
|
48
|
+
requestId,
|
|
49
|
+
userId: session.user.id,
|
|
50
|
+
degraded: true,
|
|
51
|
+
durationMs: Date.now() - started,
|
|
52
|
+
});
|
|
53
|
+
} else {
|
|
54
|
+
throw err;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const clearedAtIso =
|
|
59
|
+
clearAllState?.status === 'CLEARED'
|
|
60
|
+
? (clearAllState.clearedCutoffAt ?? clearAllState.updatedAt).toISOString()
|
|
61
|
+
: null;
|
|
62
|
+
|
|
63
|
+
logReminderEvent({
|
|
64
|
+
event: 'reminder_state_read',
|
|
65
|
+
requestId,
|
|
66
|
+
userId: session.user.id,
|
|
67
|
+
countReturned: states.filter((s) => s.reminderId !== REMINDERS_CLEAR_ALL_ID).length,
|
|
68
|
+
degraded,
|
|
69
|
+
durationMs: Date.now() - started,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
return NextResponse.json({
|
|
73
|
+
states: states.filter((state) => state.reminderId !== REMINDERS_CLEAR_ALL_ID),
|
|
74
|
+
clearedAt: clearedAtIso,
|
|
75
|
+
degraded,
|
|
76
|
+
});
|
|
77
|
+
} catch (error: unknown) {
|
|
78
|
+
const msg = error instanceof Error ? error.message : 'Erreur serveur';
|
|
79
|
+
console.error("Erreur lors de la récupération de l'état des rappels:", error);
|
|
80
|
+
return NextResponse.json({ error: msg }, { status: 500 });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export async function POST(request: NextRequest) {
|
|
85
|
+
const started = Date.now();
|
|
86
|
+
const requestId = getRequestId(request);
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
const session = await auth.api.getSession({ headers: request.headers });
|
|
90
|
+
if (!session) {
|
|
91
|
+
return NextResponse.json({ error: 'Non authentifié' }, { status: 401 });
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const body = await request.json().catch(() => ({}));
|
|
95
|
+
const reminderId = typeof body.reminderId === 'string' ? body.reminderId.trim() : '';
|
|
96
|
+
const status = typeof body.status === 'string' ? body.status.trim().toUpperCase() : '';
|
|
97
|
+
if (!reminderId) {
|
|
98
|
+
return NextResponse.json({ error: 'reminderId requis.' }, { status: 400 });
|
|
99
|
+
}
|
|
100
|
+
if (!['READ', 'DISMISSED'].includes(status)) {
|
|
101
|
+
return NextResponse.json({ error: 'status invalide.' }, { status: 400 });
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const now = new Date();
|
|
105
|
+
const expiresAt = computeExpiresAtForUpsert(reminderId, status as 'READ' | 'DISMISSED', now);
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
const state = await prisma.userReminderState.upsert({
|
|
109
|
+
where: {
|
|
110
|
+
userId_reminderId: {
|
|
111
|
+
userId: session.user.id,
|
|
112
|
+
reminderId,
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
update: {
|
|
116
|
+
status: status as 'READ' | 'DISMISSED',
|
|
117
|
+
expiresAt,
|
|
118
|
+
},
|
|
119
|
+
create: {
|
|
120
|
+
userId: session.user.id,
|
|
121
|
+
reminderId,
|
|
122
|
+
status: status as 'READ' | 'DISMISSED',
|
|
123
|
+
expiresAt,
|
|
124
|
+
},
|
|
125
|
+
select: {
|
|
126
|
+
reminderId: true,
|
|
127
|
+
status: true,
|
|
128
|
+
updatedAt: true,
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
logReminderEvent({
|
|
133
|
+
event: 'reminder_state_upsert',
|
|
134
|
+
requestId,
|
|
135
|
+
userId: session.user.id,
|
|
136
|
+
degraded: false,
|
|
137
|
+
durationMs: Date.now() - started,
|
|
138
|
+
extra: { reminderId, status },
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
return NextResponse.json({ success: true, state, degraded: false });
|
|
142
|
+
} catch (err) {
|
|
143
|
+
if (isMissingReminderStateTableError(err)) {
|
|
144
|
+
logReminderEvent({
|
|
145
|
+
event: 'reminders_fallback_missing_table',
|
|
146
|
+
requestId,
|
|
147
|
+
userId: session.user.id,
|
|
148
|
+
degraded: true,
|
|
149
|
+
durationMs: Date.now() - started,
|
|
150
|
+
});
|
|
151
|
+
return NextResponse.json({
|
|
152
|
+
success: true,
|
|
153
|
+
state: { reminderId, status, updatedAt: now.toISOString() },
|
|
154
|
+
degraded: true,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
throw err;
|
|
158
|
+
}
|
|
159
|
+
} catch (error: unknown) {
|
|
160
|
+
const msg = error instanceof Error ? error.message : 'Erreur serveur';
|
|
161
|
+
console.error("Erreur lors de la mise à jour de l'état rappel:", error);
|
|
162
|
+
return NextResponse.json({ error: msg }, { status: 500 });
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -46,21 +46,19 @@ export async function POST(request: NextRequest) {
|
|
|
46
46
|
return NextResponse.json({ error: 'Utilisateur non trouvé' }, { status: 404 });
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
// Hasher le nouveau mot de passe
|
|
50
49
|
const hashedPassword = await hashPassword(password);
|
|
51
50
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
});
|
|
51
|
+
await prisma.$transaction([
|
|
52
|
+
prisma.account.update({
|
|
53
|
+
where: { id: user.accounts[0].id },
|
|
54
|
+
data: {
|
|
55
|
+
password: hashedPassword,
|
|
56
|
+
},
|
|
57
|
+
}),
|
|
58
|
+
prisma.verification.delete({
|
|
59
|
+
where: { id: verification.id },
|
|
60
|
+
}),
|
|
61
|
+
]);
|
|
64
62
|
|
|
65
63
|
return NextResponse.json({
|
|
66
64
|
success: true,
|
|
@@ -31,7 +31,7 @@ export async function POST(request: NextRequest) {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
// Générer un code à 6 chiffres
|
|
34
|
-
const code =
|
|
34
|
+
const code = String(crypto.getRandomValues(new Uint32Array(1))[0] % 900000 + 100000);
|
|
35
35
|
|
|
36
36
|
// Créer ou mettre à jour le token de vérification
|
|
37
37
|
const expiresAt = new Date();
|
|
@@ -46,7 +46,7 @@ export async function POST(request: NextRequest) {
|
|
|
46
46
|
// Générer un token pour la réinitialisation (différent du code)
|
|
47
47
|
const resetToken = crypto.randomUUID();
|
|
48
48
|
const expiresAt = new Date();
|
|
49
|
-
expiresAt.
|
|
49
|
+
expiresAt.setMinutes(expiresAt.getMinutes() + 30); // Valide 30 minutes
|
|
50
50
|
|
|
51
51
|
// Supprimer l'ancien token de code
|
|
52
52
|
await prisma.verification.delete({
|
|
@@ -4,12 +4,10 @@ import { ResetPasswordEmailTemplate } from '@/components/reset-password-email-te
|
|
|
4
4
|
import { prisma } from '@/lib/prisma';
|
|
5
5
|
import { decrypt } from '@/lib/encryption';
|
|
6
6
|
import { auth } from '@/lib/auth';
|
|
7
|
+
import { checkPermission } from '@/lib/check-permission';
|
|
7
8
|
import nodemailer from 'nodemailer';
|
|
8
|
-
import { render } from '@react-email/render';
|
|
9
9
|
import React from 'react';
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
11
|
function htmlToText(html: string): string {
|
|
14
12
|
if (!html) return '';
|
|
15
13
|
return html
|
|
@@ -22,7 +20,6 @@ function htmlToText(html: string): string {
|
|
|
22
20
|
|
|
23
21
|
async function getAdminSmtpConfig(userId: string) {
|
|
24
22
|
try {
|
|
25
|
-
// Récupérer la configuration SMTP de l'administrateur connecté
|
|
26
23
|
const user = await prisma.user.findUnique({
|
|
27
24
|
where: { id: userId },
|
|
28
25
|
include: {
|
|
@@ -31,12 +28,10 @@ async function getAdminSmtpConfig(userId: string) {
|
|
|
31
28
|
});
|
|
32
29
|
|
|
33
30
|
if (!user) {
|
|
34
|
-
console.error('❌ Utilisateur non trouvé:', userId);
|
|
35
31
|
return { config: null, error: 'Utilisateur non trouvé' };
|
|
36
32
|
}
|
|
37
33
|
|
|
38
34
|
if (!user.smtpConfig) {
|
|
39
|
-
console.error("❌ Aucune configuration SMTP trouvée pour l'utilisateur:", user.email);
|
|
40
35
|
return {
|
|
41
36
|
config: null,
|
|
42
37
|
error:
|
|
@@ -56,8 +51,6 @@ async function getAdminSmtpConfig(userId: string) {
|
|
|
56
51
|
|
|
57
52
|
async function getAnyAdminSmtpConfig() {
|
|
58
53
|
try {
|
|
59
|
-
// Récupérer la première configuration SMTP d'un administrateur
|
|
60
|
-
// On cherche directement dans SmtpConfig et on joint avec User pour vérifier le rôle
|
|
61
54
|
const smtpConfig = await prisma.smtpConfig.findFirst({
|
|
62
55
|
where: {
|
|
63
56
|
user: {
|
|
@@ -78,15 +71,6 @@ async function getAnyAdminSmtpConfig() {
|
|
|
78
71
|
});
|
|
79
72
|
|
|
80
73
|
if (!smtpConfig) {
|
|
81
|
-
console.error('❌ Aucune configuration SMTP trouvée pour un administrateur');
|
|
82
|
-
|
|
83
|
-
// Log supplémentaire pour debug : vérifier s'il y a des admins
|
|
84
|
-
const adminCount = await prisma.user.count({
|
|
85
|
-
where: { role: 'ADMIN' },
|
|
86
|
-
});
|
|
87
|
-
const smtpConfigCount = await prisma.smtpConfig.count();
|
|
88
|
-
console.error('Debug - Admins:', adminCount, 'Configs SMTP:', smtpConfigCount);
|
|
89
|
-
|
|
90
74
|
return {
|
|
91
75
|
config: null,
|
|
92
76
|
error: 'Aucune configuration SMTP trouvée. Veuillez configurer SMTP dans les paramètres.',
|
|
@@ -108,28 +92,29 @@ export async function POST(request: Request) {
|
|
|
108
92
|
const body = await request.json();
|
|
109
93
|
const { to, subject, template, ...emailData } = body;
|
|
110
94
|
|
|
111
|
-
// Récupérer la session de l'utilisateur connecté (optionnel pour reset-password)
|
|
112
95
|
const session = await auth.api.getSession({
|
|
113
96
|
headers: request.headers,
|
|
114
97
|
});
|
|
115
98
|
|
|
116
|
-
// Pour le reset password, on n'a pas besoin de session
|
|
117
99
|
const isResetPassword = template === 'reset-password';
|
|
118
100
|
|
|
119
101
|
if (!isResetPassword && (!session || !session.user?.id)) {
|
|
120
|
-
console.error('❌ Utilisateur non authentifié');
|
|
121
102
|
return Response.json({ error: 'Non authentifié' }, { status: 401 });
|
|
122
103
|
}
|
|
123
104
|
|
|
124
|
-
|
|
105
|
+
if (!isResetPassword) {
|
|
106
|
+
const canSendEmail = await checkPermission('contacts.send_email');
|
|
107
|
+
if (!canSendEmail) {
|
|
108
|
+
return Response.json({ error: 'Accès refusé' }, { status: 403 });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
125
112
|
let smtpConfig, smtpError;
|
|
126
113
|
if (isResetPassword) {
|
|
127
|
-
// Pour le reset password, utiliser n'importe quelle config SMTP d'admin
|
|
128
114
|
const result = await getAnyAdminSmtpConfig();
|
|
129
115
|
smtpConfig = result.config;
|
|
130
116
|
smtpError = result.error;
|
|
131
117
|
} else {
|
|
132
|
-
// Pour les autres emails, utiliser la config de l'utilisateur connecté
|
|
133
118
|
const result = await getAdminSmtpConfig(session!.user.id);
|
|
134
119
|
smtpConfig = result.config;
|
|
135
120
|
smtpError = result.error;
|
|
@@ -138,12 +123,13 @@ export async function POST(request: Request) {
|
|
|
138
123
|
if (!smtpConfig) {
|
|
139
124
|
const errorMsg =
|
|
140
125
|
smtpError ||
|
|
141
|
-
'Aucune configuration SMTP trouvée. Veuillez configurer SMTP dans les paramètres.';
|
|
142
|
-
|
|
143
|
-
|
|
126
|
+
'Aucune configuration SMTP trouvée. Veuillez configurer SMTP dans les paramètres pour finaliser votre action.';
|
|
127
|
+
return Response.json(
|
|
128
|
+
{ error: errorMsg, configLink: '/settings?section=system' },
|
|
129
|
+
{ status: 400 },
|
|
130
|
+
);
|
|
144
131
|
}
|
|
145
132
|
|
|
146
|
-
// Sélectionner le template approprié et le rendre en HTML
|
|
147
133
|
let emailComponent: React.ReactElement;
|
|
148
134
|
if (template === 'invitation') {
|
|
149
135
|
emailComponent = React.createElement(InvitationEmailTemplate, {
|
|
@@ -163,23 +149,17 @@ export async function POST(request: Request) {
|
|
|
163
149
|
});
|
|
164
150
|
}
|
|
165
151
|
|
|
166
|
-
|
|
152
|
+
const { render } = await import('@react-email/render');
|
|
167
153
|
const emailHtml = await render(emailComponent);
|
|
168
154
|
const emailText = htmlToText(emailHtml);
|
|
169
155
|
|
|
170
|
-
// Déchiffrer le mot de passe SMTP
|
|
171
156
|
let password: string;
|
|
172
157
|
try {
|
|
173
158
|
password = decrypt(smtpConfig.password);
|
|
174
|
-
} catch
|
|
175
|
-
// Si le déchiffrement échoue, utiliser le mot de passe tel quel (ancien format non chiffré)
|
|
176
|
-
console.warn(
|
|
177
|
-
'⚠️ Impossible de déchiffrer le mot de passe SMTP, utilisation du mot de passe brut',
|
|
178
|
-
);
|
|
159
|
+
} catch {
|
|
179
160
|
password = smtpConfig.password;
|
|
180
161
|
}
|
|
181
162
|
|
|
182
|
-
// Créer le transporteur SMTP
|
|
183
163
|
const transporter = nodemailer.createTransport({
|
|
184
164
|
host: smtpConfig.host,
|
|
185
165
|
port: smtpConfig.port,
|
|
@@ -190,7 +170,6 @@ export async function POST(request: Request) {
|
|
|
190
170
|
},
|
|
191
171
|
});
|
|
192
172
|
|
|
193
|
-
// Envoyer l'email
|
|
194
173
|
const recipients = Array.isArray(to) ? to : [to];
|
|
195
174
|
const mailOptions = {
|
|
196
175
|
from: smtpConfig.fromName
|
|
@@ -209,21 +188,15 @@ export async function POST(request: Request) {
|
|
|
209
188
|
message: 'Email envoyé avec succès',
|
|
210
189
|
});
|
|
211
190
|
} catch (error: any) {
|
|
212
|
-
console.error("
|
|
213
|
-
console.error("Détails de l'erreur:", {
|
|
214
|
-
message: error.message,
|
|
215
|
-
code: error.code,
|
|
216
|
-
command: error.command,
|
|
217
|
-
response: error.response,
|
|
218
|
-
});
|
|
191
|
+
console.error("Erreur lors de l'envoi de l'email:", error);
|
|
219
192
|
|
|
220
|
-
// Gérer les erreurs spécifiques de nodemailer
|
|
221
193
|
if (error.code === 'EAUTH' || error.code === 'ECONNECTION') {
|
|
222
194
|
return Response.json(
|
|
223
195
|
{
|
|
224
196
|
error:
|
|
225
|
-
"Erreur d'authentification SMTP.
|
|
197
|
+
"Erreur d'authentification SMTP. Veuillez vérifier votre configuration SMTP pour finaliser votre action.",
|
|
226
198
|
details: error.message,
|
|
199
|
+
configLink: '/settings?section=system',
|
|
227
200
|
},
|
|
228
201
|
{ status: 400 },
|
|
229
202
|
);
|
|
@@ -231,8 +204,13 @@ export async function POST(request: Request) {
|
|
|
231
204
|
|
|
232
205
|
return Response.json(
|
|
233
206
|
{
|
|
234
|
-
error:
|
|
235
|
-
|
|
207
|
+
error:
|
|
208
|
+
process.env.NODE_ENV === 'development'
|
|
209
|
+
? error.message || "Erreur lors de l'envoi de l'email"
|
|
210
|
+
: "Erreur lors de l'envoi de l'email",
|
|
211
|
+
...(process.env.NODE_ENV === 'development' && {
|
|
212
|
+
details: error.code || 'UNKNOWN_ERROR',
|
|
213
|
+
}),
|
|
236
214
|
},
|
|
237
215
|
{ status: 500 },
|
|
238
216
|
);
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { NextRequest, NextResponse } from 'next/server';
|
|
2
2
|
import { prisma } from '@/lib/prisma';
|
|
3
|
-
import {
|
|
3
|
+
import { checkPermission } from '@/lib/check-permission';
|
|
4
|
+
import { auth } from '@/lib/auth';
|
|
4
5
|
|
|
5
6
|
// PUT /api/settings/closing-reasons/[id] - Mettre à jour un motif de fermeture (admin)
|
|
6
7
|
export async function PUT(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
|
7
8
|
try {
|
|
8
|
-
await
|
|
9
|
+
const session = await auth.api.getSession({ headers: request.headers });
|
|
10
|
+
if (!session) return NextResponse.json({ error: 'Non authentifié' }, { status: 401 });
|
|
11
|
+
const canManage = await checkPermission('settings.closing_reasons.manage');
|
|
12
|
+
if (!canManage) return NextResponse.json({ error: 'Accès refusé' }, { status: 403 });
|
|
9
13
|
|
|
10
14
|
const { id } = await params;
|
|
11
15
|
const body = await request.json();
|
|
@@ -32,15 +36,6 @@ export async function PUT(request: NextRequest, { params }: { params: Promise<{
|
|
|
32
36
|
});
|
|
33
37
|
} catch (error: any) {
|
|
34
38
|
console.error('Erreur lors de la mise à jour du motif de fermeture:', error);
|
|
35
|
-
|
|
36
|
-
if (error.message === 'Non authentifié') {
|
|
37
|
-
return NextResponse.json({ error: 'Non authentifié' }, { status: 401 });
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (error.message === 'Permissions insuffisantes') {
|
|
41
|
-
return NextResponse.json({ error: 'Accès refusé' }, { status: 403 });
|
|
42
|
-
}
|
|
43
|
-
|
|
44
39
|
return NextResponse.json({ error: error.message || 'Erreur serveur' }, { status: 500 });
|
|
45
40
|
}
|
|
46
41
|
}
|
|
@@ -51,7 +46,10 @@ export async function DELETE(
|
|
|
51
46
|
{ params }: { params: Promise<{ id: string }> },
|
|
52
47
|
) {
|
|
53
48
|
try {
|
|
54
|
-
await
|
|
49
|
+
const session = await auth.api.getSession({ headers: request.headers });
|
|
50
|
+
if (!session) return NextResponse.json({ error: 'Non authentifié' }, { status: 401 });
|
|
51
|
+
const canManage = await checkPermission('settings.closing_reasons.manage');
|
|
52
|
+
if (!canManage) return NextResponse.json({ error: 'Accès refusé' }, { status: 403 });
|
|
55
53
|
|
|
56
54
|
const { id } = await params;
|
|
57
55
|
|
|
@@ -65,15 +63,6 @@ export async function DELETE(
|
|
|
65
63
|
});
|
|
66
64
|
} catch (error: any) {
|
|
67
65
|
console.error('Erreur lors de la suppression du motif de fermeture:', error);
|
|
68
|
-
|
|
69
|
-
if (error.message === 'Non authentifié') {
|
|
70
|
-
return NextResponse.json({ error: 'Non authentifié' }, { status: 401 });
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (error.message === 'Permissions insuffisantes') {
|
|
74
|
-
return NextResponse.json({ error: 'Accès refusé' }, { status: 403 });
|
|
75
|
-
}
|
|
76
|
-
|
|
77
66
|
return NextResponse.json({ error: error.message || 'Erreur serveur' }, { status: 500 });
|
|
78
67
|
}
|
|
79
68
|
}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { NextRequest, NextResponse } from 'next/server';
|
|
2
2
|
import { prisma } from '@/lib/prisma';
|
|
3
|
-
import {
|
|
3
|
+
import { checkPermission } from '@/lib/check-permission';
|
|
4
|
+
import { auth } from '@/lib/auth';
|
|
4
5
|
|
|
5
6
|
// GET /api/settings/closing-reasons - Récupérer tous les motifs de fermeture (admin)
|
|
6
7
|
export async function GET(request: NextRequest) {
|
|
7
8
|
try {
|
|
8
|
-
await
|
|
9
|
+
const session = await auth.api.getSession({ headers: request.headers });
|
|
10
|
+
if (!session) return NextResponse.json({ error: 'Non authentifié' }, { status: 401 });
|
|
11
|
+
const canManage = await checkPermission('settings.closing_reasons.manage');
|
|
12
|
+
if (!canManage) return NextResponse.json({ error: 'Accès refusé' }, { status: 403 });
|
|
9
13
|
|
|
10
14
|
const reasons = await prisma.closingReason.findMany({
|
|
11
15
|
orderBy: { name: 'asc' },
|
|
@@ -14,15 +18,6 @@ export async function GET(request: NextRequest) {
|
|
|
14
18
|
return NextResponse.json(reasons);
|
|
15
19
|
} catch (error: any) {
|
|
16
20
|
console.error('Erreur lors de la récupération des motifs de fermeture:', error);
|
|
17
|
-
|
|
18
|
-
if (error.message === 'Non authentifié') {
|
|
19
|
-
return NextResponse.json({ error: 'Non authentifié' }, { status: 401 });
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (error.message === 'Permissions insuffisantes') {
|
|
23
|
-
return NextResponse.json({ error: 'Accès refusé' }, { status: 403 });
|
|
24
|
-
}
|
|
25
|
-
|
|
26
21
|
return NextResponse.json({ error: 'Erreur serveur' }, { status: 500 });
|
|
27
22
|
}
|
|
28
23
|
}
|
|
@@ -30,7 +25,10 @@ export async function GET(request: NextRequest) {
|
|
|
30
25
|
// POST /api/settings/closing-reasons - Créer un motif de fermeture (admin)
|
|
31
26
|
export async function POST(request: NextRequest) {
|
|
32
27
|
try {
|
|
33
|
-
await
|
|
28
|
+
const session = await auth.api.getSession({ headers: request.headers });
|
|
29
|
+
if (!session) return NextResponse.json({ error: 'Non authentifié' }, { status: 401 });
|
|
30
|
+
const canManage = await checkPermission('settings.closing_reasons.manage');
|
|
31
|
+
if (!canManage) return NextResponse.json({ error: 'Accès refusé' }, { status: 403 });
|
|
34
32
|
|
|
35
33
|
const body = await request.json();
|
|
36
34
|
const { name } = body;
|
|
@@ -58,15 +56,6 @@ export async function POST(request: NextRequest) {
|
|
|
58
56
|
);
|
|
59
57
|
} catch (error: any) {
|
|
60
58
|
console.error('Erreur lors de la création du motif de fermeture:', error);
|
|
61
|
-
|
|
62
|
-
if (error.message === 'Non authentifié') {
|
|
63
|
-
return NextResponse.json({ error: 'Non authentifié' }, { status: 401 });
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (error.message === 'Permissions insuffisantes') {
|
|
67
|
-
return NextResponse.json({ error: 'Accès refusé' }, { status: 403 });
|
|
68
|
-
}
|
|
69
|
-
|
|
70
59
|
return NextResponse.json({ error: error.message || 'Erreur serveur' }, { status: 500 });
|
|
71
60
|
}
|
|
72
61
|
}
|
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
import { NextRequest, NextResponse } from 'next/server';
|
|
2
2
|
import { prisma } from '@/lib/prisma';
|
|
3
|
-
import {
|
|
3
|
+
import { checkPermission } from '@/lib/check-permission';
|
|
4
|
+
import { auth } from '@/lib/auth';
|
|
4
5
|
|
|
5
6
|
// GET /api/settings/company - Récupérer les informations de l'entreprise
|
|
6
7
|
export async function GET(request: NextRequest) {
|
|
7
8
|
try {
|
|
8
|
-
await
|
|
9
|
+
const session = await auth.api.getSession({ headers: request.headers });
|
|
10
|
+
if (!session) return NextResponse.json({ error: 'Non authentifié' }, { status: 401 });
|
|
11
|
+
const hasPermission = await checkPermission('settings.view');
|
|
12
|
+
if (!hasPermission) return NextResponse.json({ error: 'Accès refusé' }, { status: 403 });
|
|
9
13
|
|
|
10
14
|
// Récupérer ou créer l'enregistrement de l'entreprise
|
|
11
|
-
let company = await prisma.
|
|
15
|
+
let company = await prisma.organization.findUnique({
|
|
12
16
|
where: { id: 'company' },
|
|
13
17
|
});
|
|
14
18
|
|
|
15
19
|
// Si l'entreprise n'existe pas, la créer
|
|
16
20
|
if (!company) {
|
|
17
|
-
company = await prisma.
|
|
21
|
+
company = await prisma.organization.create({
|
|
18
22
|
data: {
|
|
19
23
|
id: 'company',
|
|
20
24
|
},
|
|
@@ -24,15 +28,6 @@ export async function GET(request: NextRequest) {
|
|
|
24
28
|
return NextResponse.json(company);
|
|
25
29
|
} catch (error: any) {
|
|
26
30
|
console.error("Erreur lors de la récupération des informations de l'entreprise:", error);
|
|
27
|
-
|
|
28
|
-
if (error.message === 'Non authentifié') {
|
|
29
|
-
return NextResponse.json({ error: 'Non authentifié' }, { status: 401 });
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (error.message === 'Permissions insuffisantes') {
|
|
33
|
-
return NextResponse.json({ error: 'Accès refusé' }, { status: 403 });
|
|
34
|
-
}
|
|
35
|
-
|
|
36
31
|
return NextResponse.json({ error: 'Erreur serveur' }, { status: 500 });
|
|
37
32
|
}
|
|
38
33
|
}
|
|
@@ -40,11 +35,15 @@ export async function GET(request: NextRequest) {
|
|
|
40
35
|
// PUT /api/settings/company - Mettre à jour les informations de l'entreprise
|
|
41
36
|
export async function PUT(request: NextRequest) {
|
|
42
37
|
try {
|
|
43
|
-
await
|
|
38
|
+
const session = await auth.api.getSession({ headers: request.headers });
|
|
39
|
+
if (!session) return NextResponse.json({ error: 'Non authentifié' }, { status: 401 });
|
|
40
|
+
const hasPermission = await checkPermission('settings.company.edit');
|
|
41
|
+
if (!hasPermission) return NextResponse.json({ error: 'Accès refusé' }, { status: 403 });
|
|
44
42
|
|
|
45
43
|
const body = await request.json();
|
|
46
44
|
const {
|
|
47
45
|
name,
|
|
46
|
+
legalRepresentative,
|
|
48
47
|
address,
|
|
49
48
|
city,
|
|
50
49
|
postalCode,
|
|
@@ -58,16 +57,17 @@ export async function PUT(request: NextRequest) {
|
|
|
58
57
|
} = body;
|
|
59
58
|
|
|
60
59
|
// Vérifier si l'entreprise existe
|
|
61
|
-
let company = await prisma.
|
|
60
|
+
let company = await prisma.organization.findUnique({
|
|
62
61
|
where: { id: 'company' },
|
|
63
62
|
});
|
|
64
63
|
|
|
65
64
|
// Si l'entreprise n'existe pas, la créer
|
|
66
65
|
if (!company) {
|
|
67
|
-
company = await prisma.
|
|
66
|
+
company = await prisma.organization.create({
|
|
68
67
|
data: {
|
|
69
68
|
id: 'company',
|
|
70
69
|
name,
|
|
70
|
+
legalRepresentative,
|
|
71
71
|
address,
|
|
72
72
|
city,
|
|
73
73
|
postalCode,
|
|
@@ -82,10 +82,12 @@ export async function PUT(request: NextRequest) {
|
|
|
82
82
|
});
|
|
83
83
|
} else {
|
|
84
84
|
// Mettre à jour l'entreprise
|
|
85
|
-
company = await prisma.
|
|
85
|
+
company = await prisma.organization.update({
|
|
86
86
|
where: { id: 'company' },
|
|
87
87
|
data: {
|
|
88
88
|
name: name !== undefined ? name : company.name,
|
|
89
|
+
legalRepresentative:
|
|
90
|
+
legalRepresentative !== undefined ? legalRepresentative : company.legalRepresentative,
|
|
89
91
|
address: address !== undefined ? address : company.address,
|
|
90
92
|
city: city !== undefined ? city : company.city,
|
|
91
93
|
postalCode: postalCode !== undefined ? postalCode : company.postalCode,
|
|
@@ -107,15 +109,6 @@ export async function PUT(request: NextRequest) {
|
|
|
107
109
|
});
|
|
108
110
|
} catch (error: any) {
|
|
109
111
|
console.error("Erreur lors de la mise à jour des informations de l'entreprise:", error);
|
|
110
|
-
|
|
111
|
-
if (error.message === 'Non authentifié') {
|
|
112
|
-
return NextResponse.json({ error: 'Non authentifié' }, { status: 401 });
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (error.message === 'Permissions insuffisantes') {
|
|
116
|
-
return NextResponse.json({ error: 'Accès refusé' }, { status: 403 });
|
|
117
|
-
}
|
|
118
|
-
|
|
119
112
|
return NextResponse.json({ error: error.message || 'Erreur serveur' }, { status: 500 });
|
|
120
113
|
}
|
|
121
114
|
}
|