From 28445cf1a59584b9d6448ef870b1a44233508db8 Mon Sep 17 00:00:00 2001 From: Reto Aebersold Date: Tue, 9 Jan 2024 17:21:06 +0100 Subject: [PATCH 1/4] feat: add avatar upload --- .../src/pages/onboarding/AccountProfile.vue | 29 +++--- client/src/services/files.ts | 17 ++-- client/src/stores/user.ts | 5 ++ server/config/urls.py | 6 +- server/vbv_lernwelt/api/user.py | 16 +++- server/vbv_lernwelt/core/admin.py | 2 +- .../vbv_lernwelt/core/create_default_users.py | 89 +++++++++++-------- server/vbv_lernwelt/core/graphql/types.py | 3 + .../commands/create_default_users.py | 2 +- .../migrations/0004_auto_20240108_0943.py | 29 ++++++ server/vbv_lernwelt/core/models.py | 20 ++++- .../media_files/tests/test_user_images.py | 64 +++++++++++++ server/vbv_lernwelt/media_files/views.py | 39 ++++++++ 13 files changed, 260 insertions(+), 61 deletions(-) create mode 100644 server/vbv_lernwelt/core/migrations/0004_auto_20240108_0943.py create mode 100644 server/vbv_lernwelt/media_files/tests/test_user_images.py create mode 100644 server/vbv_lernwelt/media_files/views.py diff --git a/client/src/pages/onboarding/AccountProfile.vue b/client/src/pages/onboarding/AccountProfile.vue index 1eb9bb78..31b982b8 100644 --- a/client/src/pages/onboarding/AccountProfile.vue +++ b/client/src/pages/onboarding/AccountProfile.vue @@ -6,6 +6,7 @@ import { useUserStore } from "@/stores/user"; import { useRoute } from "vue-router"; import { useTranslation } from "i18next-vue"; import { profileNextRoute, useEntities } from "@/services/onboarding"; +import AvatarImage from "@/components/ui/AvatarImage.vue"; const { t } = useTranslation(); @@ -36,17 +37,23 @@ const validOrganisation = computed(() => { return selectedOrganisation.value.id !== 0; }); -/* TODO: We do this later (not in the first release) -const { - upload: avatarUpload, - loading: avatarLoading, - error: avatarError, - fileInfo: avatarFileInfo, -} = useFileUpload(); +const avatarError = ref(false); +const avatarLoading = ref(false); -watch(avatarFileInfo, (info) => { - console.log("fileInfo changed", info); -})*/ +async function avatarUpload(e: Event) { + const { files } = e.target as HTMLInputElement; + if (!files?.length) return; + avatarLoading.value = true; + avatarError.value = false; + + try { + await user.setUserAvatar(files[0]); + } catch (e) { + avatarError.value = true; + } finally { + avatarLoading.value = false; + } +} watch(selectedOrganisation, async (organisation) => { await user.setUserOrganisation(organisation.id); @@ -74,7 +81,6 @@ const nextRoute = computed(() => { -