diff --git a/cookbook/serializer.py b/cookbook/serializer.py index c62fdc407..6c991e436 100644 --- a/cookbook/serializer.py +++ b/cookbook/serializer.py @@ -37,7 +37,7 @@ from cookbook.models import (Automation, BookmarkletImport, Comment, CookLog, Cu SupermarketCategoryRelation, Sync, SyncLog, Unit, UnitConversion, UserFile, UserPreference, UserSpace, ViewLog, ConnectorConfig) from cookbook.templatetags.custom_tags import markdown -from recipes.settings import AWS_ENABLED, MEDIA_URL +from recipes.settings import AWS_ENABLED, MEDIA_URL, EMAIL_HOST class WritableNestedModelSerializer(WNMS): @@ -1338,7 +1338,7 @@ class InviteLinkSerializer(WritableNestedModelSerializer): validated_data['space'] = self.context['request'].space obj = super().create(validated_data) - if obj.email: + if obj.email and EMAIL_HOST is not '': try: if InviteLink.objects.filter(space=self.context['request'].space, created_at__gte=datetime.now() - timedelta(hours=4)).count() < 20: diff --git a/vue3/src/components/settings/SpaceMemberSettings.vue b/vue3/src/components/settings/SpaceMemberSettings.vue index 6525a7151..47e1520fd 100644 --- a/vue3/src/components/settings/SpaceMemberSettings.vue +++ b/vue3/src/components/settings/SpaceMemberSettings.vue @@ -3,16 +3,14 @@

{{ $t('SpaceMembers') }}

- - + - @@ -21,25 +19,28 @@ {{ $t('Created') }} {{ DateTime.fromJSDate(spaceUserEditDialogUserSpace.createdAt).toLocaleString(DateTime.DATETIME_MED) }} - +
-

{{$t('Note')}}

- {{spaceUserEditDialogUserSpace.internalNote}} +

{{ $t('Note') }}

+ {{ spaceUserEditDialogUserSpace.internalNote }}
- {{ $t('Cancel') }} + {{ $t('Cancel') }} {{ $t('Save') }}
-

{{ $t('Invites') }} {{$t('New')}}

+

{{ $t('Invites') }} + {{ $t('New') }} +

@@ -47,7 +48,7 @@ - {{$t('Invites')}} + {{ $t('Invites') }} @@ -59,8 +60,12 @@ - {{ $t('Cancel') }} - {{ $t('Create') }} + {{ $t('Cancel') }} + + {{ $t('Create') }} + {{ $t('Update') }} + + {{ $t('Delete') }} @@ -77,7 +82,8 @@ import {ApiApi, Group, InviteLink, UserSpace} from "@/openapi"; import {ErrorMessageType, PreparedMessage, useMessageStore} from "@/stores/MessageStore"; import {useI18n} from "vue-i18n"; import {DateTime} from "luxon"; -import {VDateInput} from 'vuetify/labs/VDateInput' //TODO remove once component is out of labs +import {VDateInput} from 'vuetify/labs/VDateInput' +import {useClipboard} from "@vueuse/core"; //TODO remove once component is out of labs const {t} = useI18n() @@ -90,6 +96,7 @@ const spaceUserEditDialogUserSpace = ref({} as UserSpace) const inviteLinkDialogState = ref(false) const inviteLinkDialogObject = ref({} as InviteLink) +const inviteLinkDialogLoading = ref(false) const userTableHeaders = [ {title: t('Username'), key: 'user.username'}, @@ -126,28 +133,78 @@ onMounted(() => { }) }) +/** + * update user space in DB and list on client + * @param userSpace UserSpace object to update + */ function updateUserSpace(userSpace: UserSpace) { const api = new ApiApi() api.apiUserSpacePartialUpdate({id: userSpace.id!, patchedUserSpace: userSpace}).then(r => { - + spaceUserSpaces.value.splice(spaceUserSpaces.value.indexOf(userSpace), 1, r) + useMessageStore().addPreparedMessage(PreparedMessage.UPDATE_SUCCESS) }).catch(err => { useMessageStore().addError(ErrorMessageType.UPDATE_ERROR, err) }) } -function createInviteLink(inviteLink: InviteLink){ +/** + * create or update the invite link, refresh invite link list on client + * @param inviteLink InviteLink object to update + */ +function saveInviteLink(inviteLink: InviteLink) { const api = new ApiApi() - api.apiInviteLinkCreate({inviteLink: inviteLink}).then(r => { + inviteLinkDialogLoading.value = true + + if (inviteLink.id == undefined) { + api.apiInviteLinkCreate({inviteLink: inviteLink}).then(r => { + inviteLinkDialogState.value = false + spaceInviteLinks.value.push(r) + useMessageStore().addPreparedMessage(PreparedMessage.CREATE_SUCCESS) + }).catch(err => { + useMessageStore().addError(ErrorMessageType.CREATE_ERROR, err) + }).finally(() => { + inviteLinkDialogLoading.value = false + }) + } else { + api.apiInviteLinkUpdate({inviteLink: inviteLink, id: inviteLink.id}).then(r => { + inviteLinkDialogState.value = false + spaceInviteLinks.value.splice(spaceInviteLinks.value.indexOf(inviteLink), 1, r) + useMessageStore().addPreparedMessage(PreparedMessage.UPDATE_SUCCESS) + }).catch(err => { + useMessageStore().addError(ErrorMessageType.UPDATE_ERROR, err) + }).finally(() => { + inviteLinkDialogLoading.value = false + }) + } + +} + +/** + * delete invite link from database and client + * @param inviteLink InviteLink object to delete + */ +function deleteInviteLink(inviteLink: InviteLink) { + const api = new ApiApi() + api.apiInviteLinkDestroy({id: inviteLink.id}).then(r => { inviteLinkDialogState.value = false - spaceInviteLinks.value.push(r) - useMessageStore().addPreparedMessage(PreparedMessage.CREATE_SUCCESS) + spaceInviteLinks.value.splice(spaceInviteLinks.value.indexOf(inviteLink) - 1, 1) + useMessageStore().addPreparedMessage(PreparedMessage.DELETE_SUCCESS) }).catch(err => { - useMessageStore().addError(ErrorMessageType.CREATE_ERROR, err) + useMessageStore().addError(ErrorMessageType.UPDATE_ERROR, err) }) } +/** + * copy invite link with url to clipboard + * @param inviteLink InviteLink object to copy + */ +function copyInviteLink(inviteLink: InviteLink) { + const {copy} = useClipboard() + copy(`${location.protocol}//${location.host}/invite/${inviteLink.uuid}`) +} +