@hed-hog/core 0.0.303 → 0.0.305
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/README.md +84 -36
- package/dist/auth/auth.controller.d.ts +0 -3
- package/dist/auth/auth.controller.d.ts.map +1 -1
- package/dist/auth/auth.controller.js +4 -7
- package/dist/auth/auth.controller.js.map +1 -1
- package/dist/auth/auth.service.d.ts.map +1 -1
- package/dist/auth/auth.service.js +6 -3
- package/dist/auth/auth.service.js.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts +9 -0
- package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.controller.js +12 -0
- package/dist/dashboard/dashboard-core/dashboard-core.controller.js.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts +7 -0
- package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts.map +1 -1
- package/dist/dashboard/dashboard-core/dashboard-core.service.js +45 -1
- package/dist/dashboard/dashboard-core/dashboard-core.service.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/mail-sent/dto/query-mail-sent-list.dto.d.ts +9 -0
- package/dist/mail-sent/dto/query-mail-sent-list.dto.d.ts.map +1 -0
- package/dist/mail-sent/dto/query-mail-sent-list.dto.js +49 -0
- package/dist/mail-sent/dto/query-mail-sent-list.dto.js.map +1 -0
- package/dist/mail-sent/mail-sent.controller.d.ts +24 -2
- package/dist/mail-sent/mail-sent.controller.d.ts.map +1 -1
- package/dist/mail-sent/mail-sent.controller.js +5 -3
- package/dist/mail-sent/mail-sent.controller.js.map +1 -1
- package/dist/mail-sent/mail-sent.service.d.ts +28 -3
- package/dist/mail-sent/mail-sent.service.d.ts.map +1 -1
- package/dist/mail-sent/mail-sent.service.js +108 -3
- package/dist/mail-sent/mail-sent.service.js.map +1 -1
- package/dist/oauth/oauth-callback-coordinator.service.d.ts +18 -0
- package/dist/oauth/oauth-callback-coordinator.service.d.ts.map +1 -0
- package/dist/oauth/oauth-callback-coordinator.service.js +137 -0
- package/dist/oauth/oauth-callback-coordinator.service.js.map +1 -0
- package/dist/oauth/oauth.controller.d.ts +4 -2
- package/dist/oauth/oauth.controller.d.ts.map +1 -1
- package/dist/oauth/oauth.controller.js +39 -11
- package/dist/oauth/oauth.controller.js.map +1 -1
- package/dist/oauth/oauth.errors.d.ts +16 -0
- package/dist/oauth/oauth.errors.d.ts.map +1 -0
- package/dist/oauth/oauth.errors.js +30 -0
- package/dist/oauth/oauth.errors.js.map +1 -0
- package/dist/oauth/oauth.module.d.ts.map +1 -1
- package/dist/oauth/oauth.module.js +10 -1
- package/dist/oauth/oauth.module.js.map +1 -1
- package/dist/oauth/oauth.service.d.ts +9 -1
- package/dist/oauth/oauth.service.d.ts.map +1 -1
- package/dist/oauth/oauth.service.js +97 -24
- package/dist/oauth/oauth.service.js.map +1 -1
- package/dist/oauth/providers/abstract.provider.d.ts +6 -0
- package/dist/oauth/providers/abstract.provider.d.ts.map +1 -1
- package/dist/oauth/providers/abstract.provider.js +34 -0
- package/dist/oauth/providers/abstract.provider.js.map +1 -1
- package/dist/oauth/providers/microsoft-entra-id.provider.d.ts +3 -0
- package/dist/oauth/providers/microsoft-entra-id.provider.d.ts.map +1 -1
- package/dist/oauth/providers/microsoft-entra-id.provider.js +40 -22
- package/dist/oauth/providers/microsoft-entra-id.provider.js.map +1 -1
- package/dist/security/security.service.d.ts +1 -0
- package/dist/security/security.service.d.ts.map +1 -1
- package/dist/security/security.service.js +9 -10
- package/dist/security/security.service.js.map +1 -1
- package/dist/session/session.service.d.ts +5 -1
- package/dist/session/session.service.d.ts.map +1 -1
- package/dist/session/session.service.js +76 -10
- package/dist/session/session.service.js.map +1 -1
- package/dist/setting/setting.service.js +4 -4
- package/dist/setting/setting.service.js.map +1 -1
- package/dist/token/token.service.d.ts +1 -0
- package/dist/token/token.service.d.ts.map +1 -1
- package/dist/token/token.service.js +23 -12
- package/dist/token/token.service.js.map +1 -1
- package/dist/user/user.service.d.ts +1 -1
- package/dist/user/user.service.d.ts.map +1 -1
- package/dist/user/user.service.js +3 -0
- package/dist/user/user.service.js.map +1 -1
- package/hedhog/data/dashboard.yaml +2 -2
- package/hedhog/data/mail.yaml +147 -0
- package/hedhog/data/route.yaml +8 -0
- package/hedhog/frontend/app/account/components/change-email-form.tsx.ejs +87 -8
- package/hedhog/frontend/app/account/components/profile-form.tsx.ejs +90 -10
- package/hedhog/frontend/app/ai_agent/page.tsx.ejs +145 -31
- package/hedhog/frontend/app/configurations/layout.tsx.ejs +1 -1
- package/hedhog/frontend/app/dashboard/[slug]/dashboard-content.tsx.ejs +67 -2
- package/hedhog/frontend/app/dashboard/components/add-widget-selector-dialog.tsx.ejs +13 -9
- package/hedhog/frontend/app/dashboard/dashboard-home-tabs.tsx.ejs +250 -45
- package/hedhog/frontend/app/dashboard/management/tabs/component-roles-tab.tsx.ejs +111 -15
- package/hedhog/frontend/app/dashboard/management/tabs/dashboard-roles-tab.tsx.ejs +110 -15
- package/hedhog/frontend/app/dashboard/management/tabs/items-tab.tsx.ejs +113 -15
- package/hedhog/frontend/app/mail/log/page.tsx.ejs +481 -70
- package/hedhog/frontend/app/menu/page.tsx.ejs +202 -30
- package/hedhog/frontend/app/roles/menus.tsx.ejs +1 -1
- package/hedhog/frontend/app/roles/page.tsx.ejs +288 -104
- package/hedhog/frontend/app/users/page.tsx.ejs +168 -23
- package/hedhog/frontend/messages/en.json +45 -6
- package/hedhog/frontend/messages/pt.json +45 -6
- package/package.json +4 -4
- package/src/auth/auth.controller.ts +15 -19
- package/src/auth/auth.service.ts +13 -8
- package/src/dashboard/dashboard-core/dashboard-core.controller.ts +22 -9
- package/src/dashboard/dashboard-core/dashboard-core.service.ts +75 -1
- package/src/index.ts +10 -7
- package/src/mail-sent/dto/query-mail-sent-list.dto.ts +30 -0
- package/src/mail-sent/mail-sent.controller.ts +14 -2
- package/src/mail-sent/mail-sent.service.ts +159 -4
- package/src/oauth/oauth-callback-coordinator.service.ts +158 -0
- package/src/oauth/oauth.controller.ts +58 -1
- package/src/oauth/oauth.errors.ts +32 -0
- package/src/oauth/oauth.module.ts +10 -1
- package/src/oauth/oauth.service.ts +178 -28
- package/src/oauth/providers/abstract.provider.ts +64 -0
- package/src/oauth/providers/microsoft-entra-id.provider.ts +92 -56
- package/src/security/security.service.ts +12 -10
- package/src/session/session.service.ts +84 -9
- package/src/setting/setting.service.ts +10 -10
- package/src/token/token.service.ts +29 -11
- package/src/user/user.service.ts +10 -6
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
FormLabel,
|
|
36
36
|
FormMessage,
|
|
37
37
|
} from '@/components/ui/form';
|
|
38
|
+
import { FormActions } from '@/components/ui/form-actions';
|
|
38
39
|
import { Input } from '@/components/ui/input';
|
|
39
40
|
import {
|
|
40
41
|
Sheet,
|
|
@@ -43,6 +44,7 @@ import {
|
|
|
43
44
|
SheetHeader,
|
|
44
45
|
SheetTitle,
|
|
45
46
|
} from '@/components/ui/sheet';
|
|
47
|
+
import { useFormDraft } from '@/hooks/use-form-draft';
|
|
46
48
|
import { formatDateTime } from '@/lib/format-date';
|
|
47
49
|
import { getPhotoUrl } from '@/lib/get-photo-url';
|
|
48
50
|
import { getUserEmail } from '@/lib/get-user-email';
|
|
@@ -79,8 +81,8 @@ import {
|
|
|
79
81
|
Users,
|
|
80
82
|
} from 'lucide-react';
|
|
81
83
|
import { useTranslations } from 'next-intl';
|
|
82
|
-
import { useEffect, useState } from 'react';
|
|
83
|
-
import { useForm } from 'react-hook-form';
|
|
84
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
85
|
+
import { useForm, useWatch } from 'react-hook-form';
|
|
84
86
|
import { toast } from 'sonner';
|
|
85
87
|
import { z } from 'zod';
|
|
86
88
|
import { ActiveSessions } from './active-session';
|
|
@@ -96,6 +98,24 @@ type RequestResponse<T> = {
|
|
|
96
98
|
};
|
|
97
99
|
};
|
|
98
100
|
|
|
101
|
+
type UserCreateDraftPayload = {
|
|
102
|
+
values: {
|
|
103
|
+
name: string;
|
|
104
|
+
email: string;
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
type UserEditDraftPayload = {
|
|
109
|
+
userId: number | null;
|
|
110
|
+
values: {
|
|
111
|
+
name: string;
|
|
112
|
+
email: string;
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const USER_CREATE_DRAFT_STORAGE_KEY = 'core-user-create-draft';
|
|
117
|
+
const USER_EDIT_DRAFT_STORAGE_KEY = 'core-user-edit-draft';
|
|
118
|
+
|
|
99
119
|
export default function UserPage() {
|
|
100
120
|
const t = useTranslations('core.UserPage');
|
|
101
121
|
const userActivityT = useTranslations('core.UserActivity');
|
|
@@ -198,6 +218,108 @@ export default function UserPage() {
|
|
|
198
218
|
},
|
|
199
219
|
});
|
|
200
220
|
|
|
221
|
+
const watchedCreateValues = useWatch({
|
|
222
|
+
control: form.control,
|
|
223
|
+
});
|
|
224
|
+
const watchedEditValues = useWatch({
|
|
225
|
+
control: editForm.control,
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
const {
|
|
229
|
+
clearDraft: clearCreateDraft,
|
|
230
|
+
loadDraft: loadCreateDraft,
|
|
231
|
+
hasDraft: hasCreateDraft,
|
|
232
|
+
savedAt: createDraftSavedAt,
|
|
233
|
+
} = useFormDraft<UserCreateDraftPayload>({
|
|
234
|
+
storageKey: USER_CREATE_DRAFT_STORAGE_KEY,
|
|
235
|
+
value: {
|
|
236
|
+
values: {
|
|
237
|
+
name: watchedCreateValues.name ?? '',
|
|
238
|
+
email: watchedCreateValues.email ?? '',
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
hasData: Boolean(
|
|
242
|
+
(watchedCreateValues.name ?? '').trim() ||
|
|
243
|
+
(watchedCreateValues.email ?? '').trim()
|
|
244
|
+
),
|
|
245
|
+
enabled: isDialogOpen,
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
const {
|
|
249
|
+
clearDraft: clearEditDraft,
|
|
250
|
+
loadDraft: loadEditDraft,
|
|
251
|
+
hasDraft: hasEditDraft,
|
|
252
|
+
savedAt: editDraftSavedAt,
|
|
253
|
+
} = useFormDraft<UserEditDraftPayload>({
|
|
254
|
+
storageKey: USER_EDIT_DRAFT_STORAGE_KEY,
|
|
255
|
+
value: {
|
|
256
|
+
userId: editingUser?.id ? Number(editingUser.id) : null,
|
|
257
|
+
values: {
|
|
258
|
+
name: watchedEditValues.name ?? '',
|
|
259
|
+
email: watchedEditValues.email ?? '',
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
hasData: Boolean(
|
|
263
|
+
(watchedEditValues.name ?? '').trim() ||
|
|
264
|
+
(watchedEditValues.email ?? '').trim()
|
|
265
|
+
),
|
|
266
|
+
enabled: Boolean(editingUser),
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
const createDraftStatusContent = useMemo(() => {
|
|
270
|
+
if (!hasCreateDraft || !createDraftSavedAt) {
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const savedDate = new Date(createDraftSavedAt);
|
|
275
|
+
|
|
276
|
+
if (Number.isNaN(savedDate.getTime())) {
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const locale = currentLocaleCode === 'en' ? enUS : ptBR;
|
|
281
|
+
const relativeLabel = formatDistanceToNow(savedDate, {
|
|
282
|
+
addSuffix: true,
|
|
283
|
+
locale,
|
|
284
|
+
});
|
|
285
|
+
const absoluteLabel = formatDateTime(
|
|
286
|
+
savedDate,
|
|
287
|
+
getSettingValue,
|
|
288
|
+
currentLocaleCode
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
return currentLocaleCode === 'en'
|
|
292
|
+
? `Draft saved ${relativeLabel} • Last saved: ${absoluteLabel}`
|
|
293
|
+
: `Rascunho salvo ${relativeLabel} • Último salvamento: ${absoluteLabel}`;
|
|
294
|
+
}, [createDraftSavedAt, currentLocaleCode, getSettingValue, hasCreateDraft]);
|
|
295
|
+
|
|
296
|
+
const editDraftStatusContent = useMemo(() => {
|
|
297
|
+
if (!hasEditDraft || !editDraftSavedAt) {
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const savedDate = new Date(editDraftSavedAt);
|
|
302
|
+
|
|
303
|
+
if (Number.isNaN(savedDate.getTime())) {
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const locale = currentLocaleCode === 'en' ? enUS : ptBR;
|
|
308
|
+
const relativeLabel = formatDistanceToNow(savedDate, {
|
|
309
|
+
addSuffix: true,
|
|
310
|
+
locale,
|
|
311
|
+
});
|
|
312
|
+
const absoluteLabel = formatDateTime(
|
|
313
|
+
savedDate,
|
|
314
|
+
getSettingValue,
|
|
315
|
+
currentLocaleCode
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
return currentLocaleCode === 'en'
|
|
319
|
+
? `Draft saved ${relativeLabel} • Last saved: ${absoluteLabel}`
|
|
320
|
+
: `Rascunho salvo ${relativeLabel} • Último salvamento: ${absoluteLabel}`;
|
|
321
|
+
}, [editDraftSavedAt, currentLocaleCode, getSettingValue, hasEditDraft]);
|
|
322
|
+
|
|
201
323
|
const [activeTab, setActiveTab] = useState('overview');
|
|
202
324
|
const [openDeleteModal, setOpenDeleteModal] = useState(false);
|
|
203
325
|
|
|
@@ -246,13 +368,35 @@ export default function UserPage() {
|
|
|
246
368
|
|
|
247
369
|
useEffect(() => {
|
|
248
370
|
if (editingUser) {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
371
|
+
const storedDraft = loadEditDraft();
|
|
372
|
+
const shouldRestoreDraft =
|
|
373
|
+
storedDraft?.payload.userId === Number(editingUser.id);
|
|
374
|
+
|
|
375
|
+
editForm.reset(
|
|
376
|
+
shouldRestoreDraft
|
|
377
|
+
? storedDraft.payload.values
|
|
378
|
+
: {
|
|
379
|
+
name: editingUser.name || '',
|
|
380
|
+
email: getUserEmail(editingUser),
|
|
381
|
+
}
|
|
382
|
+
);
|
|
253
383
|
setActiveTab('overview');
|
|
254
384
|
}
|
|
255
|
-
}, [editingUser]);
|
|
385
|
+
}, [editForm, editingUser, loadEditDraft]);
|
|
386
|
+
|
|
387
|
+
useEffect(() => {
|
|
388
|
+
if (!isDialogOpen) {
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const storedDraft = loadCreateDraft();
|
|
393
|
+
|
|
394
|
+
form.reset({
|
|
395
|
+
name: storedDraft?.payload.values.name ?? '',
|
|
396
|
+
email: storedDraft?.payload.values.email ?? '',
|
|
397
|
+
password: '',
|
|
398
|
+
});
|
|
399
|
+
}, [form, isDialogOpen, loadCreateDraft]);
|
|
256
400
|
|
|
257
401
|
const onSubmit = async (values: z.infer<typeof addUserSchema>) => {
|
|
258
402
|
try {
|
|
@@ -261,6 +405,7 @@ export default function UserPage() {
|
|
|
261
405
|
method: 'POST',
|
|
262
406
|
data: values,
|
|
263
407
|
});
|
|
408
|
+
clearCreateDraft();
|
|
264
409
|
form.reset();
|
|
265
410
|
refetch();
|
|
266
411
|
setIsDialogOpen(false);
|
|
@@ -324,6 +469,7 @@ export default function UserPage() {
|
|
|
324
469
|
method: 'PATCH',
|
|
325
470
|
data: values,
|
|
326
471
|
});
|
|
472
|
+
clearEditDraft();
|
|
327
473
|
refetch();
|
|
328
474
|
setEditFormError(null);
|
|
329
475
|
toast.success(t('userUpdatedSuccess'));
|
|
@@ -773,9 +919,13 @@ export default function UserPage() {
|
|
|
773
919
|
</Alert>
|
|
774
920
|
)}
|
|
775
921
|
|
|
776
|
-
<
|
|
777
|
-
|
|
778
|
-
|
|
922
|
+
<FormActions
|
|
923
|
+
sheet
|
|
924
|
+
statusContent={createDraftStatusContent}
|
|
925
|
+
submitLabel={t('buttonAddUser')}
|
|
926
|
+
submitType="submit"
|
|
927
|
+
sheetClassName="px-0 pb-0"
|
|
928
|
+
/>
|
|
779
929
|
</form>
|
|
780
930
|
</Form>
|
|
781
931
|
</SheetContent>
|
|
@@ -1210,19 +1360,14 @@ export default function UserPage() {
|
|
|
1210
1360
|
</FormItem>
|
|
1211
1361
|
)}
|
|
1212
1362
|
/>
|
|
1213
|
-
<
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
onClick={() => setEditingUser(null)}
|
|
1222
|
-
>
|
|
1223
|
-
{t('cancel')}
|
|
1224
|
-
</Button>
|
|
1225
|
-
</div>
|
|
1363
|
+
<FormActions
|
|
1364
|
+
statusContent={editDraftStatusContent}
|
|
1365
|
+
cancelLabel={t('cancel')}
|
|
1366
|
+
onCancel={() => setEditingUser(null)}
|
|
1367
|
+
submitLabel={t('saveChanges')}
|
|
1368
|
+
submitType="submit"
|
|
1369
|
+
className="pt-2"
|
|
1370
|
+
/>
|
|
1226
1371
|
</form>
|
|
1227
1372
|
</Form>
|
|
1228
1373
|
</TabsContent>
|
|
@@ -495,7 +495,8 @@
|
|
|
495
495
|
"errorTitle": "Unable to authenticate",
|
|
496
496
|
"buttonRetry": "Try again",
|
|
497
497
|
"loading": "Loading...",
|
|
498
|
-
"errorOccurred": "An error occurred."
|
|
498
|
+
"errorOccurred": "An error occurred.",
|
|
499
|
+
"alreadyProcessed": "This authentication callback has already been processed. Start the flow again."
|
|
499
500
|
},
|
|
500
501
|
"github": {
|
|
501
502
|
"loginTitle": "Completing login...",
|
|
@@ -510,7 +511,8 @@
|
|
|
510
511
|
"errorTitle": "Unable to authenticate",
|
|
511
512
|
"buttonRetry": "Try again",
|
|
512
513
|
"loading": "Loading...",
|
|
513
|
-
"errorOccurred": "An error occurred."
|
|
514
|
+
"errorOccurred": "An error occurred.",
|
|
515
|
+
"alreadyProcessed": "This authentication callback has already been processed. Start the flow again."
|
|
514
516
|
},
|
|
515
517
|
"facebook": {
|
|
516
518
|
"loginTitle": "Completing login...",
|
|
@@ -525,7 +527,8 @@
|
|
|
525
527
|
"errorTitle": "Unable to authenticate",
|
|
526
528
|
"buttonRetry": "Try again",
|
|
527
529
|
"loading": "Loading...",
|
|
528
|
-
"errorOccurred": "An error occurred."
|
|
530
|
+
"errorOccurred": "An error occurred.",
|
|
531
|
+
"alreadyProcessed": "This authentication callback has already been processed. Start the flow again."
|
|
529
532
|
},
|
|
530
533
|
"microsoft": {
|
|
531
534
|
"loginTitle": "Completing login...",
|
|
@@ -540,7 +543,8 @@
|
|
|
540
543
|
"errorTitle": "Unable to authenticate",
|
|
541
544
|
"buttonRetry": "Try again",
|
|
542
545
|
"loading": "Loading...",
|
|
543
|
-
"errorOccurred": "An error occurred."
|
|
546
|
+
"errorOccurred": "An error occurred.",
|
|
547
|
+
"alreadyProcessed": "This authentication callback has already been processed. Start the flow again."
|
|
544
548
|
},
|
|
545
549
|
"microsoft-entra-id": {
|
|
546
550
|
"loginTitle": "Completing login...",
|
|
@@ -555,7 +559,8 @@
|
|
|
555
559
|
"errorTitle": "Unable to authenticate",
|
|
556
560
|
"buttonRetry": "Try again",
|
|
557
561
|
"loading": "Loading...",
|
|
558
|
-
"errorOccurred": "An error occurred."
|
|
562
|
+
"errorOccurred": "An error occurred.",
|
|
563
|
+
"alreadyProcessed": "This authentication callback has already been processed. Start the flow again."
|
|
559
564
|
}
|
|
560
565
|
},
|
|
561
566
|
"ConnectedAccounts": {
|
|
@@ -866,7 +871,41 @@
|
|
|
866
871
|
"bcc": "BCC",
|
|
867
872
|
"body": "Body",
|
|
868
873
|
"createdAt": "Created At",
|
|
869
|
-
"updatedAt": "Updated At"
|
|
874
|
+
"updatedAt": "Updated At",
|
|
875
|
+
"id": "ID",
|
|
876
|
+
"actions": "Actions",
|
|
877
|
+
"delivery": "Delivery",
|
|
878
|
+
"loadingLogs": "Loading email logs...",
|
|
879
|
+
"recipientPlaceholder": "Filter by recipient",
|
|
880
|
+
"clearFilters": "Clear filters",
|
|
881
|
+
"viewMode": "View mode",
|
|
882
|
+
"viewModeTable": "Table",
|
|
883
|
+
"viewModeCards": "Cards",
|
|
884
|
+
"filterByStatus": "Filter by status",
|
|
885
|
+
"filterByError": "Filter by error",
|
|
886
|
+
"statusAll": "All statuses",
|
|
887
|
+
"statusReceived": "Received",
|
|
888
|
+
"statusRead": "Read",
|
|
889
|
+
"statusError": "Error",
|
|
890
|
+
"statusUnavailable": "No status",
|
|
891
|
+
"statusReceivedShort": "Received: {count}",
|
|
892
|
+
"statusReadShort": "Read: {count}",
|
|
893
|
+
"statusErrorShort": "Errors: {count}",
|
|
894
|
+
"status_received": "Received",
|
|
895
|
+
"status_read": "Read",
|
|
896
|
+
"status_error": "Error",
|
|
897
|
+
"errorAll": "All",
|
|
898
|
+
"errorOnly": "Only with error",
|
|
899
|
+
"errorNone": "Without error",
|
|
900
|
+
"hasError": "With error",
|
|
901
|
+
"withoutError": "Without error",
|
|
902
|
+
"totalRecipientsCurrentPage": "Recipients (page)",
|
|
903
|
+
"readRecipientsCurrentPage": "Read (page)",
|
|
904
|
+
"emailsWithErrorCurrentPage": "Emails with error (page)",
|
|
905
|
+
"totalRecipientsLabel": "Recipients: {count}",
|
|
906
|
+
"noRecipientStatus": "No recipient tracking available for this delivery.",
|
|
907
|
+
"readAt": "Read at",
|
|
908
|
+
"errorMessage": "Error message"
|
|
870
909
|
},
|
|
871
910
|
"Configurations": {
|
|
872
911
|
"breadcrumbHome": "Home",
|
|
@@ -495,7 +495,8 @@
|
|
|
495
495
|
"errorTitle": "Não foi possível autenticar",
|
|
496
496
|
"buttonRetry": "Tentar novamente",
|
|
497
497
|
"loading": "Carregando...",
|
|
498
|
-
"errorOccurred": "Ocorreu um erro."
|
|
498
|
+
"errorOccurred": "Ocorreu um erro.",
|
|
499
|
+
"alreadyProcessed": "Esta autenticacao ja foi processada. Inicie o fluxo novamente."
|
|
499
500
|
},
|
|
500
501
|
"github": {
|
|
501
502
|
"loginTitle": "Finalizando login...",
|
|
@@ -510,7 +511,8 @@
|
|
|
510
511
|
"errorTitle": "Não foi possível autenticar",
|
|
511
512
|
"buttonRetry": "Tentar novamente",
|
|
512
513
|
"loading": "Carregando...",
|
|
513
|
-
"errorOccurred": "Ocorreu um erro."
|
|
514
|
+
"errorOccurred": "Ocorreu um erro.",
|
|
515
|
+
"alreadyProcessed": "Esta autenticacao ja foi processada. Inicie o fluxo novamente."
|
|
514
516
|
},
|
|
515
517
|
"facebook": {
|
|
516
518
|
"loginTitle": "Finalizando login...",
|
|
@@ -525,7 +527,8 @@
|
|
|
525
527
|
"errorTitle": "Não foi possível autenticar",
|
|
526
528
|
"buttonRetry": "Tentar novamente",
|
|
527
529
|
"loading": "Carregando...",
|
|
528
|
-
"errorOccurred": "Ocorreu um erro."
|
|
530
|
+
"errorOccurred": "Ocorreu um erro.",
|
|
531
|
+
"alreadyProcessed": "Esta autenticacao ja foi processada. Inicie o fluxo novamente."
|
|
529
532
|
},
|
|
530
533
|
"microsoft": {
|
|
531
534
|
"loginTitle": "Finalizando login...",
|
|
@@ -540,7 +543,8 @@
|
|
|
540
543
|
"errorTitle": "Não foi possível autenticar",
|
|
541
544
|
"buttonRetry": "Tentar novamente",
|
|
542
545
|
"loading": "Carregando...",
|
|
543
|
-
"errorOccurred": "Ocorreu um erro."
|
|
546
|
+
"errorOccurred": "Ocorreu um erro.",
|
|
547
|
+
"alreadyProcessed": "Esta autenticacao ja foi processada. Inicie o fluxo novamente."
|
|
544
548
|
},
|
|
545
549
|
"microsoft-entra-id": {
|
|
546
550
|
"loginTitle": "Finalizando login...",
|
|
@@ -555,7 +559,8 @@
|
|
|
555
559
|
"errorTitle": "Não foi possível autenticar",
|
|
556
560
|
"buttonRetry": "Tentar novamente",
|
|
557
561
|
"loading": "Carregando...",
|
|
558
|
-
"errorOccurred": "Ocorreu um erro."
|
|
562
|
+
"errorOccurred": "Ocorreu um erro.",
|
|
563
|
+
"alreadyProcessed": "Esta autenticacao ja foi processada. Inicie o fluxo novamente."
|
|
559
564
|
}
|
|
560
565
|
},
|
|
561
566
|
"ConnectedAccounts": {
|
|
@@ -869,7 +874,41 @@
|
|
|
869
874
|
"bcc": "CCO",
|
|
870
875
|
"body": "Corpo",
|
|
871
876
|
"createdAt": "Criado em",
|
|
872
|
-
"updatedAt": "Atualizado em"
|
|
877
|
+
"updatedAt": "Atualizado em",
|
|
878
|
+
"id": "ID",
|
|
879
|
+
"actions": "Ações",
|
|
880
|
+
"delivery": "Entrega",
|
|
881
|
+
"loadingLogs": "Carregando logs de e-mail...",
|
|
882
|
+
"recipientPlaceholder": "Filtrar por destinatário",
|
|
883
|
+
"clearFilters": "Limpar filtros",
|
|
884
|
+
"viewMode": "Visualização",
|
|
885
|
+
"viewModeTable": "Tabela",
|
|
886
|
+
"viewModeCards": "Cards",
|
|
887
|
+
"filterByStatus": "Filtrar por status",
|
|
888
|
+
"filterByError": "Filtrar por erro",
|
|
889
|
+
"statusAll": "Todos os status",
|
|
890
|
+
"statusReceived": "Recebido",
|
|
891
|
+
"statusRead": "Lido",
|
|
892
|
+
"statusError": "Erro",
|
|
893
|
+
"statusUnavailable": "Sem status",
|
|
894
|
+
"statusReceivedShort": "Recebidos: {count}",
|
|
895
|
+
"statusReadShort": "Lidos: {count}",
|
|
896
|
+
"statusErrorShort": "Erros: {count}",
|
|
897
|
+
"status_received": "Recebido",
|
|
898
|
+
"status_read": "Lido",
|
|
899
|
+
"status_error": "Erro",
|
|
900
|
+
"errorAll": "Todos",
|
|
901
|
+
"errorOnly": "Apenas com erro",
|
|
902
|
+
"errorNone": "Sem erro",
|
|
903
|
+
"hasError": "Com erro",
|
|
904
|
+
"withoutError": "Sem erro",
|
|
905
|
+
"totalRecipientsCurrentPage": "Destinatários (página)",
|
|
906
|
+
"readRecipientsCurrentPage": "Lidos (página)",
|
|
907
|
+
"emailsWithErrorCurrentPage": "E-mails com erro (página)",
|
|
908
|
+
"totalRecipientsLabel": "Destinatários: {count}",
|
|
909
|
+
"noRecipientStatus": "Sem rastreamento por destinatário para este envio.",
|
|
910
|
+
"readAt": "Lido em",
|
|
911
|
+
"errorMessage": "Mensagem de erro"
|
|
873
912
|
},
|
|
874
913
|
"Configurations": {
|
|
875
914
|
"breadcrumbHome": "Início",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hed-hog/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.305",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"dependencies": {
|
|
@@ -30,12 +30,12 @@
|
|
|
30
30
|
"sharp": "^0.34.2",
|
|
31
31
|
"speakeasy": "^2.0.0",
|
|
32
32
|
"uuid": "^11.1.0",
|
|
33
|
-
"@hed-hog/api": "0.0.
|
|
33
|
+
"@hed-hog/api-pagination": "0.0.7",
|
|
34
34
|
"@hed-hog/api-locale": "0.0.14",
|
|
35
35
|
"@hed-hog/api-mail": "0.0.9",
|
|
36
36
|
"@hed-hog/api-prisma": "0.0.6",
|
|
37
|
-
"@hed-hog/api
|
|
38
|
-
"@hed-hog/api-
|
|
37
|
+
"@hed-hog/api": "0.0.6",
|
|
38
|
+
"@hed-hog/api-types": "0.0.1"
|
|
39
39
|
},
|
|
40
40
|
"exports": {
|
|
41
41
|
".": {
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import { Public, Role, User, UserOptional } from '@hed-hog/api';
|
|
2
2
|
import { Locale } from '@hed-hog/api-locale';
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
UnauthorizedException,
|
|
4
|
+
Body,
|
|
5
|
+
Controller,
|
|
6
|
+
forwardRef,
|
|
7
|
+
Get,
|
|
8
|
+
Headers,
|
|
9
|
+
Inject,
|
|
10
|
+
Ip,
|
|
11
|
+
Post,
|
|
12
|
+
Req,
|
|
13
|
+
Res,
|
|
14
|
+
UnauthorizedException
|
|
16
15
|
} from '@nestjs/common';
|
|
17
16
|
import { TokenService } from '../token/token.service';
|
|
18
17
|
import { CreateWithEmailAndPasswordDTO } from '../user/dto/create-with-email-and-password.dto';
|
|
@@ -64,13 +63,10 @@ export class AuthController {
|
|
|
64
63
|
const { session, refreshToken, accessToken } = await this.service.refreshAccessToken(locale, currentRefreshToken, ipAddress, userAgent);
|
|
65
64
|
await this.token.setRefreshTokenCookie(locale, res, refreshToken, session.expires_at);
|
|
66
65
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
return { accessToken };
|
|
66
|
+
return {
|
|
67
|
+
accessToken,
|
|
68
|
+
refreshToken,
|
|
69
|
+
};
|
|
74
70
|
}
|
|
75
71
|
|
|
76
72
|
@Public()
|
package/src/auth/auth.service.ts
CHANGED
|
@@ -2,12 +2,12 @@ import { getLocaleText } from '@hed-hog/api-locale';
|
|
|
2
2
|
import { PrismaService } from '@hed-hog/api-prisma';
|
|
3
3
|
import { User } from '@hed-hog/api-types';
|
|
4
4
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
BadRequestException,
|
|
6
|
+
forwardRef,
|
|
7
|
+
Inject,
|
|
8
|
+
Injectable,
|
|
9
|
+
NotFoundException,
|
|
10
|
+
UnauthorizedException,
|
|
11
11
|
} from '@nestjs/common';
|
|
12
12
|
import { ChallengeService } from '../challenge/challenge.service';
|
|
13
13
|
import { MailService as MailManagerService } from '../mail/mail.service';
|
|
@@ -509,8 +509,13 @@ export class AuthService {
|
|
|
509
509
|
}
|
|
510
510
|
|
|
511
511
|
async logout(res, req, refreshToken: string) {
|
|
512
|
-
await this.session.deleteRefreshTokenCookie(res, refreshToken);
|
|
513
|
-
|
|
512
|
+
const result = await this.session.deleteRefreshTokenCookie(res, refreshToken);
|
|
513
|
+
const logoutUserId = req.auth?.sub ?? result?.userId ?? null;
|
|
514
|
+
|
|
515
|
+
if (logoutUserId) {
|
|
516
|
+
await this.user.registerUserActivity(logoutUserId, 'logout');
|
|
517
|
+
}
|
|
518
|
+
|
|
514
519
|
return { success: true };
|
|
515
520
|
}
|
|
516
521
|
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { Role, User } from '@hed-hog/api';
|
|
2
2
|
import { Locale } from '@hed-hog/api-locale';
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
4
|
+
Body,
|
|
5
|
+
Controller,
|
|
6
|
+
Delete,
|
|
7
|
+
Get,
|
|
8
|
+
Param,
|
|
9
|
+
ParseIntPipe,
|
|
10
|
+
Patch,
|
|
11
|
+
Post,
|
|
12
|
+
Query,
|
|
13
13
|
} from '@nestjs/common';
|
|
14
14
|
import { DashboardCoreService } from './dashboard-core.service';
|
|
15
15
|
|
|
@@ -67,6 +67,19 @@ export class DashboardCoreController {
|
|
|
67
67
|
return this.dashboardCoreService.createUserDashboard(user.id, body, locale);
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
@Patch('dashboard/order')
|
|
71
|
+
reorderUserDashboards(
|
|
72
|
+
@User() user,
|
|
73
|
+
@Body() body: { slugs?: string[] },
|
|
74
|
+
@Locale() locale: string,
|
|
75
|
+
) {
|
|
76
|
+
return this.dashboardCoreService.reorderUserDashboards(
|
|
77
|
+
user.id,
|
|
78
|
+
body.slugs,
|
|
79
|
+
locale,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
70
83
|
@Patch('dashboard/:slug')
|
|
71
84
|
renameUserDashboard(
|
|
72
85
|
@User() user,
|
|
@@ -1602,7 +1602,7 @@ export class DashboardCoreService {
|
|
|
1602
1602
|
},
|
|
1603
1603
|
},
|
|
1604
1604
|
},
|
|
1605
|
-
orderBy: [{
|
|
1605
|
+
orderBy: [{ updated_at: 'asc' }, { id: 'asc' }],
|
|
1606
1606
|
});
|
|
1607
1607
|
|
|
1608
1608
|
const uniqueByDashboardId = new Map<number, (typeof dashboardUsers)[number]>();
|
|
@@ -1622,6 +1622,80 @@ export class DashboardCoreService {
|
|
|
1622
1622
|
}));
|
|
1623
1623
|
}
|
|
1624
1624
|
|
|
1625
|
+
async reorderUserDashboards(userId: number, slugs: string[] | undefined, locale: string) {
|
|
1626
|
+
const normalizedSlugs = Array.from(
|
|
1627
|
+
new Set(
|
|
1628
|
+
(Array.isArray(slugs) ? slugs : [])
|
|
1629
|
+
.map((slug) => this.toNullableString(slug))
|
|
1630
|
+
.filter((slug): slug is string => Boolean(slug)),
|
|
1631
|
+
),
|
|
1632
|
+
);
|
|
1633
|
+
|
|
1634
|
+
if (normalizedSlugs.length === 0) {
|
|
1635
|
+
throw new BadRequestException(
|
|
1636
|
+
getLocaleText(
|
|
1637
|
+
'validation.fieldRequired',
|
|
1638
|
+
locale,
|
|
1639
|
+
'Dashboard order is required.',
|
|
1640
|
+
),
|
|
1641
|
+
);
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
const dashboardUsers = await this.prismaService.dashboard_user.findMany({
|
|
1645
|
+
where: { user_id: userId },
|
|
1646
|
+
include: {
|
|
1647
|
+
dashboard: {
|
|
1648
|
+
select: {
|
|
1649
|
+
slug: true,
|
|
1650
|
+
},
|
|
1651
|
+
},
|
|
1652
|
+
},
|
|
1653
|
+
orderBy: [{ updated_at: 'asc' }, { id: 'asc' }],
|
|
1654
|
+
});
|
|
1655
|
+
|
|
1656
|
+
if (dashboardUsers.length === 0) {
|
|
1657
|
+
return { success: true };
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
const dashboardBySlug = new Map(
|
|
1661
|
+
dashboardUsers.map((dashboardUser) => [dashboardUser.dashboard.slug, dashboardUser]),
|
|
1662
|
+
);
|
|
1663
|
+
|
|
1664
|
+
for (const slug of normalizedSlugs) {
|
|
1665
|
+
if (!dashboardBySlug.has(slug)) {
|
|
1666
|
+
throw new ForbiddenException(
|
|
1667
|
+
getLocaleText('dashboardNotFound', locale, 'Dashboard not found.'),
|
|
1668
|
+
);
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
const normalizedSlugSet = new Set(normalizedSlugs);
|
|
1673
|
+
const orderedDashboardUsers = [
|
|
1674
|
+
...normalizedSlugs.map((slug) => dashboardBySlug.get(slug)!),
|
|
1675
|
+
...dashboardUsers.filter(
|
|
1676
|
+
(dashboardUser) => !normalizedSlugSet.has(dashboardUser.dashboard.slug),
|
|
1677
|
+
),
|
|
1678
|
+
];
|
|
1679
|
+
|
|
1680
|
+
const baseTimestamp = Date.now();
|
|
1681
|
+
|
|
1682
|
+
await this.prismaService.$transaction(
|
|
1683
|
+
orderedDashboardUsers.map((dashboardUser, index) =>
|
|
1684
|
+
this.prismaService.dashboard_user.update({
|
|
1685
|
+
where: { id: dashboardUser.id },
|
|
1686
|
+
data: {
|
|
1687
|
+
updated_at: new Date(baseTimestamp + index),
|
|
1688
|
+
},
|
|
1689
|
+
}),
|
|
1690
|
+
),
|
|
1691
|
+
);
|
|
1692
|
+
|
|
1693
|
+
return {
|
|
1694
|
+
success: true,
|
|
1695
|
+
orderedSlugs: orderedDashboardUsers.map((dashboardUser) => dashboardUser.dashboard.slug),
|
|
1696
|
+
};
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1625
1699
|
async getAvailableTemplates(userId: number, locale: string) {
|
|
1626
1700
|
const userRoleIds = await this.getUserRoleIds(userId);
|
|
1627
1701
|
const templateAccessFilter =
|