Skip to content

Commit 7f35375

Browse files
committed
feat: add undelete identities functionality to backend and frontend
#98 - Implemented a new endpoint in BackendsController to restore deleted identities. - Added corresponding service method in BackendsService to handle identity restoration logic. - Enhanced the trash page and identity detail view in the frontend to include a button for restoring identities, with permission checks and user notifications for success or failure.
1 parent 78a5bcb commit 7f35375

File tree

4 files changed

+141
-0
lines changed

4 files changed

+141
-0
lines changed

apps/api/src/core/backends/backends.controller.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,21 @@ export class BackendsController {
6565
return res.status(HttpStatus.ACCEPTED).json({ async, data });
6666
}
6767

68+
@Post('undelete')
69+
@ApiOperation({ summary: "Restaure une liste d'identitées supprimées" })
70+
public async undeleteIdentities(
71+
@Res() res: Response,
72+
@Body() body: DeleteIdentitiesDto,
73+
@Query('async') asyncQuery: string,
74+
) {
75+
const async = /true|on|yes|1/i.test(asyncQuery);
76+
const data = await this.backendsService.undeleteIdentities(body.payload, {
77+
async,
78+
});
79+
80+
return res.status(HttpStatus.ACCEPTED).json({ async, data });
81+
}
82+
6883
@Post('sync')
6984
@ApiOperation({ summary: "Synchronise une liste d'identitées" })
7085
public async syncIdentities(

apps/api/src/core/backends/backends.service.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,35 @@ export class BackendsService extends AbstractQueueProcessor {
347347
return result;
348348
}
349349

350+
public async undeleteIdentities(payload: string[], options?: ExecuteJobOptions): Promise<any> {
351+
const result = {};
352+
void options;
353+
354+
if (!payload.length) throw new BadRequestException('No identities to restore');
355+
356+
for (const key of payload) {
357+
const identity = await this.identitiesService.findById<any>(key);
358+
if (!identity) {
359+
throw new BadRequestException({
360+
status: HttpStatus.BAD_REQUEST,
361+
message: `Identity ${key} not found`,
362+
});
363+
}
364+
365+
const targetState = identity.lastBackendSync ? IdentityState.TO_SYNC : IdentityState.TO_CREATE;
366+
await this.identitiesService.model.findByIdAndUpdate(key, {
367+
$set: {
368+
state: targetState,
369+
deletedFlag: false,
370+
dataStatus: DataStatusEnum.ACTIVE,
371+
},
372+
});
373+
result[identity._id] = { restored: true, state: targetState };
374+
}
375+
376+
return result;
377+
}
378+
350379
public async disableIdentities(payload: string[], options?: ExecuteJobOptions): Promise<any> {
351380
const identities: {
352381
action: ActionType;

apps/web/src/pages/identities/trash.vue

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,26 @@ q-page.grid
1919
sesame-pages-identities-states-info(:identity='props.row')
2020
template(v-slot:row-actions='{ row }')
2121
q-btn(:to='toPathWithQueries(`/identities/trash/${row._id}`)' color='primary' icon='mdi-eye' size='sm' flat round dense)
22+
q-btn(
23+
color='orange-8'
24+
icon='mdi-restore'
25+
size='sm'
26+
flat
27+
round
28+
dense
29+
:disable='!hasPermission("/management/identities", "update")'
30+
@click='undeleteIdentity(row)'
31+
)
32+
q-tooltip.text-body2.bg-negative.text-white(
33+
v-if='!hasPermission("/management/identities", "update")'
34+
anchor='top middle'
35+
self='center middle'
36+
) Vous n'avez pas les permissions nécessaires pour effectuer cette action
37+
q-tooltip.text-body2.bg-orange-8.text-white(
38+
v-else
39+
anchor='top middle'
40+
self='center middle'
41+
) Restaurer l'identité
2242
template(#after-content)
2343
nuxt-page(ref='page' @refresh='refresh')
2444
</template>
@@ -34,6 +54,7 @@ export default defineNuxtComponent({
3454
async setup() {
3555
const page = ref<typeof Page | null>(null)
3656
const $route = useRoute()
57+
const { hasPermission } = useAccessControl()
3758
const { getDefaults } = usePagination()
3859
const { debug } = useDebug()
3960
@@ -71,6 +92,7 @@ export default defineNuxtComponent({
7192
return {
7293
debug,
7394
page,
95+
hasPermission,
7496
identities,
7597
pending,
7698
refresh,
@@ -107,5 +129,32 @@ export default defineNuxtComponent({
107129
},
108130
},
109131
},
132+
methods: {
133+
async undeleteIdentity(identity) {
134+
try {
135+
await this.$http.post('/core/backends/undelete', {
136+
body: {
137+
payload: [identity._id],
138+
},
139+
})
140+
141+
this.$q.notify({
142+
message: "L'identité a été restaurée.",
143+
color: 'positive',
144+
position: 'top-right',
145+
icon: 'mdi-check-circle-outline',
146+
})
147+
await this.fetchAllStateCount()
148+
this.refresh()
149+
} catch (error: any) {
150+
this.$q.notify({
151+
message: "Impossible de restaurer l'identité : " + (error?.response?._data?.message || 'erreur inconnue'),
152+
color: 'negative',
153+
position: 'top-right',
154+
icon: 'mdi-alert-circle-outline',
155+
})
156+
}
157+
},
158+
},
110159
})
111160
</script>

apps/web/src/pages/identities/trash/[_id].vue

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,25 @@ q-card.flex.column.fit.absolute(flat)
88
sesame-pages-identities-states-info.q-mx-sm(:identity='identity')
99
q-toolbar-title.q-pa-none.cursor-pointer(@click='navigateToTab(`/identities/trash/${identity._id}`)')
1010
span(v-text='identity?.inetOrgPerson?.cn || "Identité sans nom"')
11+
q-btn.q-mr-sm(
12+
color='orange-8'
13+
icon='mdi-restore'
14+
flat
15+
round
16+
dense
17+
:disable='!hasPermission("/management/identities", "update")'
18+
@click='undeleteIdentity()'
19+
)
20+
q-tooltip.text-body2.bg-negative.text-white(
21+
v-if='!hasPermission("/management/identities", "update")'
22+
anchor='top middle'
23+
self='center middle'
24+
) Vous n'avez pas les permissions nécessaires pour effectuer cette action
25+
q-tooltip.text-body2.bg-orange-8.text-white(
26+
v-else
27+
anchor='top middle'
28+
self='center middle'
29+
) Restaurer l'identité
1130
q-separator(v-for='_ in 2' :key='_')
1231
q-card-section.col.q-pa-none.overflow-auto
1332
.column.no-wrap.full-height
@@ -58,6 +77,7 @@ export default defineNuxtComponent({
5877
async setup() {
5978
const $route = useRoute()
6079
const { navigateToTab } = useRouteQueries()
80+
const { hasPermission } = useAccessControl()
6181
const identityStateStore = useIdentityStateStore()
6282
6383
const {
@@ -85,6 +105,8 @@ export default defineNuxtComponent({
85105
identity,
86106
refresh,
87107
navigateToTab,
108+
hasPermission,
109+
fetchAllStateCount: identityStateStore.fetchAllStateCount,
88110
}
89111
},
90112
computed: {
@@ -103,6 +125,32 @@ export default defineNuxtComponent({
103125
},
104126
},
105127
methods: {
128+
async undeleteIdentity() {
129+
try {
130+
await this.$http.post('/core/backends/undelete', {
131+
body: {
132+
payload: [this.identity._id],
133+
},
134+
})
135+
136+
this.$q.notify({
137+
message: "L'identité a été restaurée.",
138+
color: 'positive',
139+
position: 'top-right',
140+
icon: 'mdi-check-circle-outline',
141+
})
142+
await this.fetchAllStateCount()
143+
this.$emit('refresh')
144+
this.navigateToTab('/identities/trash')
145+
} catch (error: any) {
146+
this.$q.notify({
147+
message: "Impossible de restaurer l'identité : " + (error?.response?._data?.message || 'erreur inconnue'),
148+
color: 'negative',
149+
position: 'top-right',
150+
icon: 'mdi-alert-circle-outline',
151+
})
152+
}
153+
},
106154
async save() {
107155
try {
108156
await this.$http.patch(`/management/identities/${this.identity._id}`, {

0 commit comments

Comments
 (0)