Skip to content
Merged

2.2.0 #268

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion apps/api/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,13 @@ app.use(
helmet({
contentSecurityPolicy: {
directives: {
'img-src': ["'self'", '*.githubusercontent.com', 'data:', 'dlrgbrahmseedigitalprod.blob.core.windows.net'],
'img-src': [
"'self'",
'*.githubusercontent.com',
'blob:',
'data:',
'dlrgbrahmseedigitalprod.blob.core.windows.net',
],
'connect-src': ["'self'", 'dlrgbrahmseedigitalprod.blob.core.windows.net'],
},
},
Expand Down
5 changes: 3 additions & 2 deletions apps/api/src/services/customFields/customFields.router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { customFieldsList } from './customFieldsList.js'
import { customFieldsTemplates } from './customFieldsTemplates.js'
import { customFieldsUnterveranstaltungCreate } from './customFieldsUnterveranstaltungCreate.js'
import { customFieldsVeranstaltungCreate } from './customFieldsVeranstaltungCreate.js'
import { customFieldsDelete } from './customFieldsDelete.js'
import { customFieldsVeranstaltungDelete, customFieldsUnterveranstaltungDelete } from './customFieldsDelete.js'
import { customFieldsUpdate } from './customFieldsUpdate.js'
import { customFieldValuesUpdate } from './customFieldValuesUpdate.js'
// Import Routes here - do not delete this line
Expand All @@ -16,7 +16,8 @@ export const customFieldsRouter = mergeRouters(
customFieldsGet.router,
customFieldsVeranstaltungCreate.router,
customFieldsUpdate.router,
customFieldsDelete.router,
customFieldsVeranstaltungDelete.router,
customFieldsUnterveranstaltungDelete.router,
customFieldsUnterveranstaltungCreate.router,
customFieldValuesUpdate.router,
customFieldsTemplates.router
Expand Down
39 changes: 21 additions & 18 deletions apps/api/src/services/customFields/customFieldsDelete.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,34 @@
import { Role } from '@prisma/client'
import { TRPCError } from '@trpc/server'
import { z } from 'zod'

import prisma from '../../prisma.js'
import { defineProtectedMutateProcedure } from '../../types/defineProcedure.js'
import { TRPCError } from '@trpc/server'

export const customFieldsDelete = defineProtectedMutateProcedure({
key: 'delete',
roleIds: [Role.ADMIN, Role.GLIEDERUNG_ADMIN],
export const customFieldsVeranstaltungDelete = defineProtectedMutateProcedure({
key: 'veranstaltungDelete',
roleIds: [Role.ADMIN],
inputSchema: z.strictObject({
veranstaltungId: z.number(),
fieldId: z.number(),
}),
async handler({ input }) {
await prisma.customField.delete({
where: {
id: input.fieldId,
veranstaltungId: input.veranstaltungId,
},
})
},
})

export const customFieldsUnterveranstaltungDelete = defineProtectedMutateProcedure({
key: 'unterveranstaltungDelete',
roleIds: [Role.ADMIN, Role.GLIEDERUNG_ADMIN],
inputSchema: z.strictObject({
unterveranstaltungId: z.number(),
fieldId: z.number(),
}),
async handler({ ctx, input }) {
if (ctx.account.role === Role.GLIEDERUNG_ADMIN) {
const { gliederungId: gliederungIdActor } = await prisma.person.findFirstOrThrow({
Expand Down Expand Up @@ -43,23 +60,9 @@ export const customFieldsDelete = defineProtectedMutateProcedure({
}
}

const field = await prisma.customField.findUnique({
where: {
id: input.fieldId,
veranstaltungId: input.veranstaltungId,
},
})

if (field === null) {
throw new TRPCError({
code: 'NOT_FOUND',
})
}

await prisma.customField.delete({
where: {
id: input.fieldId,
veranstaltungId: input.veranstaltungId,
},
})
},
Expand Down
115 changes: 115 additions & 0 deletions apps/frontend/src/components/CustomFields/CustomFieldDeleteModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<script setup lang="ts">
import { useTemplateRef } from 'vue'
import Button from '../UIComponents/Button.vue'
import Modal, { type ModalApi } from '../UIComponents/Modal.vue'
import { useAsyncState } from '@vueuse/core'
import type { RouterOutput } from '@codeanker/api'
import { apiClient } from '@/api'

type Props = {
entity: 'veranstaltung' | 'unterveranstaltung'
entityId: number
field: RouterOutput['customFields']['get']
}

type Emits = {
delete: []
}

const props = defineProps<Props>()
const emit = defineEmits<Emits>()

const modal = useTemplateRef('modal')

const {
execute: doDelete,
error: errorDelete,
isLoading: isDeleting,
} = useAsyncState(
async () => {
if (!props.field) {
return
}

switch (props.entity) {
case 'veranstaltung':
await apiClient.customFields.veranstaltungDelete.mutate({
fieldId: props.field.id,
veranstaltungId: props.entityId,
})
break
case 'unterveranstaltung':
await apiClient.customFields.unterveranstaltungDelete.mutate({
fieldId: props.field.id,
unterveranstaltungId: props.entityId,
})
break
default:
break
}

emit('delete')
},
null,
{ immediate: false }
)

defineExpose<ModalApi>({
show(ctx) {
if (isDeleting) {
return
}

modal.value?.show(ctx)
},
hide(ctx) {
if (isDeleting) {
return
}

modal.value?.hide(ctx)
},
})
</script>

<template>
<Teleport to="body">
<Modal ref="modal">
<template #content>
<div class="space-y-8">
<div>
<p class="text-xl font-bold">Benutzerdefiniertes Feld &quot;{{ field.name }}&quot; löschen</p>
<p>
Wenn du das benutzerdefinierte Feld löschst, gehen sämtliche damit verbundenen Eingaben aus den
Anmeldungen unwiderruflich verloren.
</p>
<p>Bist du sicher, dass du das Feld löschen möchtest?</p>
</div>

<p
v-if="errorDelete"
class="my-4"
>
{{ errorDelete }}
</p>

<div class="flex gap-x-4 justify-end">
<Button
type="button"
@click="modal?.hide()"
>
Feld behalten
</Button>
<Button
type="button"
color="danger"
@click="doDelete"
>
Feld löschen
</Button>
</div>
</div>
</template>
</Modal>
</Teleport>
</template>
41 changes: 19 additions & 22 deletions apps/frontend/src/components/CustomFields/CustomFieldsFormEdit.vue
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
<script setup lang="ts">
import { useAsyncState } from '@vueuse/core'
import { ref, watch } from 'vue'
import { ref, useTemplateRef, watch } from 'vue'

import { apiClient } from '@/api'
import CustomFieldsFormGeneral, { type ICustomFieldData } from '@/components/CustomFields/CustomFieldsFormGeneral.vue'
import Button from '@/components/UIComponents/Button.vue'
import router from '@/router'
import type { CustomFieldType } from '@codeanker/api'
import { ValidateForm } from '@codeanker/validation'
import CustomFieldDeleteModal from './CustomFieldDeleteModal.vue'

const props = defineProps<{
entity: 'veranstaltung' | 'unterveranstaltung'
entityId: number
fieldId: number
}>()

const deleteModal = useTemplateRef('deleteModal')

const { state: field } = useAsyncState(async () => {
return apiClient.customFields.get.query({
id: props.fieldId,
Expand Down Expand Up @@ -72,23 +77,6 @@ const {
null,
{ immediate: false }
)

const {
execute: doDelete,
// error: errorDelete,
isLoading: isDeleting,
} = useAsyncState(
async () => {
await apiClient.customFields.delete.mutate({
fieldId: field.value!.id,
veranstaltungId: 0,
})

router.back()
},
null,
{ immediate: false }
)
</script>

<template>
Expand All @@ -101,15 +89,15 @@ const {
<Button
type="submit"
color="primary"
:disabled="isUpdating || isDeleting"
:disabled="isUpdating"
>
<span v-if="!isUpdating">Speichern</span>
<span v-else>Loading...</span>
</Button>
<Button
type="button"
color="warning"
:disabled="isUpdating || isDeleting"
:disabled="isUpdating"
@click="() => router.back()"
>
Abbrechen
Expand All @@ -118,8 +106,8 @@ const {
<Button
type="button"
color="danger"
:disabled="isUpdating || isDeleting"
@click="doDelete"
:disabled="isUpdating"
@click="deleteModal?.show()"
>
Löschen
</Button>
Expand All @@ -137,4 +125,13 @@ const {
{{ error }}
</div>
</div>

<CustomFieldDeleteModal
v-if="field"
ref="deleteModal"
:entity="props.entity"
:entity-id="props.entityId"
:field="field"
@delete="router.back()"
/>
</template>
Loading