From 3fa846966ee35ae90d90c4ebf314fd4928451318 Mon Sep 17 00:00:00 2001 From: Ewen Le Bihan Date: Thu, 17 Oct 2024 15:30:10 +0200 Subject: [PATCH 1/2] feat(shop): drop shops (shops will come back as a separate project) --- .changeset/wild-cycles-eat.md | 6 + .old-app-routes/bookings/+page.gql | 12 - .old-app-routes/bookings/+page.svelte | 72 --- .../bookings/[pseudoID].pdf/+server.ts | 7 - .../bookings/[pseudoID]/+page.server.ts | 114 ---- .../bookings/[pseudoID]/+page.svelte | 492 ----------------- .../groups/[uid]/shop/shop/+page.svelte | 102 ---- .../groups/[uid]/shop/shop/+page.ts | 49 -- .../groups/[uid]/shop/shop/[id]/+page.svelte | 331 ----------- .../groups/[uid]/shop/shop/[id]/+page.ts | 53 -- .../[uid]/shop/shop/[id]/edit/+page.gql | 57 -- .../[uid]/shop/shop/[id]/edit/+page.svelte | 41 -- .../groups/[uid]/shop/shop/[id]/edit/+page.ts | 17 - .../[uid]/shop/shop/create/+page.svelte | 36 -- .../groups/[uid]/shop/shop/create/+page.ts | 57 -- .../[uid]/shop/shop/orders/+page.svelte | 87 --- .../groups/[uid]/shop/shop/orders/+page.ts | 44 -- .../groups/[uid]/shop/shop/sales/+page.svelte | 50 -- .../groups/[uid]/shop/shop/sales/+page.ts | 50 -- .../shop/shop/sales/[itemUid]/+page.svelte | 51 -- .../[uid]/shop/shop/sales/[itemUid]/+page.ts | 42 -- .old-app-routes/users/[uid]/+page.svelte | 516 ------------------ .old-app-routes/users/[uid]/+page.ts | 166 ------ packages/api/.graphinx.yaml | 1 - packages/api/barrelsby.config.json | 3 - packages/api/src/lib/global-id.ts | 5 - packages/api/src/lib/pictures.ts | 9 +- .../src/modules/payments/utils/lydia/pay.ts | 67 +-- packages/api/src/modules/shop/README.md | 7 - packages/api/src/modules/shop/icon.svg | 6 - packages/api/src/modules/shop/index.ts | 11 - .../modules/shop/resolvers/group.shop-item.ts | 34 -- .../shop/resolvers/group.shop-items.ts | 45 -- .../shop/resolvers/group.shop-orders.ts | 34 -- .../api/src/modules/shop/resolvers/index.ts | 17 - .../resolvers/mutation.delete-item-picture.ts | 35 -- .../resolvers/mutation.delete-shop-item.ts | 53 -- .../resolvers/mutation.delete-shop-option.ts | 26 - .../resolvers/mutation.paid-shop-payment.ts | 127 ----- .../resolvers/mutation.update-item-picture.ts | 49 -- .../resolvers/mutation.upsert-shop-item.ts | 121 ---- .../resolvers/mutation.upsert-shop-options.ts | 51 -- .../resolvers/mutation.upsert-shop-payment.ts | 185 ------- .../modules/shop/resolvers/query.shop-item.ts | 80 --- .../shop/resolvers/query.shop-payments.ts | 59 -- packages/api/src/modules/shop/types/index.ts | 10 - .../api/src/modules/shop/types/picture.ts | 9 - .../modules/shop/types/shop-item-answer.ts | 10 - .../shop/types/shop-item-option-input.ts | 11 - .../modules/shop/types/shop-item-option.ts | 12 - .../api/src/modules/shop/types/shop-item.ts | 144 ----- .../src/modules/shop/types/shop-payment.ts | 18 - packages/api/src/modules/shop/utils/index.ts | 6 - .../api/src/modules/shop/utils/permissions.ts | 44 -- packages/api/src/modules/shop/utils/uid.ts | 14 - packages/api/src/schema.ts | 1 - packages/api/src/server/lydia.ts | 20 - packages/app/schema.graphql | 150 ----- packages/app/src/lib/typenames.ts | 5 - .../20241017131441_drop_shop/migration.sql | 192 +++++++ packages/db/prisma/schema.prisma | 74 --- packages/db/seed/index.ts | 44 -- 62 files changed, 201 insertions(+), 4040 deletions(-) create mode 100644 .changeset/wild-cycles-eat.md delete mode 100644 .old-app-routes/bookings/+page.gql delete mode 100644 .old-app-routes/bookings/+page.svelte delete mode 100644 .old-app-routes/bookings/[pseudoID].pdf/+server.ts delete mode 100644 .old-app-routes/bookings/[pseudoID]/+page.server.ts delete mode 100644 .old-app-routes/bookings/[pseudoID]/+page.svelte delete mode 100644 .old-app-routes/groups/[uid]/shop/shop/+page.svelte delete mode 100644 .old-app-routes/groups/[uid]/shop/shop/+page.ts delete mode 100644 .old-app-routes/groups/[uid]/shop/shop/[id]/+page.svelte delete mode 100644 .old-app-routes/groups/[uid]/shop/shop/[id]/+page.ts delete mode 100644 .old-app-routes/groups/[uid]/shop/shop/[id]/edit/+page.gql delete mode 100644 .old-app-routes/groups/[uid]/shop/shop/[id]/edit/+page.svelte delete mode 100644 .old-app-routes/groups/[uid]/shop/shop/[id]/edit/+page.ts delete mode 100644 .old-app-routes/groups/[uid]/shop/shop/create/+page.svelte delete mode 100644 .old-app-routes/groups/[uid]/shop/shop/create/+page.ts delete mode 100644 .old-app-routes/groups/[uid]/shop/shop/orders/+page.svelte delete mode 100644 .old-app-routes/groups/[uid]/shop/shop/orders/+page.ts delete mode 100644 .old-app-routes/groups/[uid]/shop/shop/sales/+page.svelte delete mode 100644 .old-app-routes/groups/[uid]/shop/shop/sales/+page.ts delete mode 100644 .old-app-routes/groups/[uid]/shop/shop/sales/[itemUid]/+page.svelte delete mode 100644 .old-app-routes/groups/[uid]/shop/shop/sales/[itemUid]/+page.ts delete mode 100644 .old-app-routes/users/[uid]/+page.svelte delete mode 100644 .old-app-routes/users/[uid]/+page.ts delete mode 100644 packages/api/src/modules/shop/README.md delete mode 100644 packages/api/src/modules/shop/icon.svg delete mode 100644 packages/api/src/modules/shop/index.ts delete mode 100644 packages/api/src/modules/shop/resolvers/group.shop-item.ts delete mode 100644 packages/api/src/modules/shop/resolvers/group.shop-items.ts delete mode 100644 packages/api/src/modules/shop/resolvers/group.shop-orders.ts delete mode 100644 packages/api/src/modules/shop/resolvers/index.ts delete mode 100644 packages/api/src/modules/shop/resolvers/mutation.delete-item-picture.ts delete mode 100644 packages/api/src/modules/shop/resolvers/mutation.delete-shop-item.ts delete mode 100644 packages/api/src/modules/shop/resolvers/mutation.delete-shop-option.ts delete mode 100644 packages/api/src/modules/shop/resolvers/mutation.paid-shop-payment.ts delete mode 100644 packages/api/src/modules/shop/resolvers/mutation.update-item-picture.ts delete mode 100644 packages/api/src/modules/shop/resolvers/mutation.upsert-shop-item.ts delete mode 100644 packages/api/src/modules/shop/resolvers/mutation.upsert-shop-options.ts delete mode 100644 packages/api/src/modules/shop/resolvers/mutation.upsert-shop-payment.ts delete mode 100644 packages/api/src/modules/shop/resolvers/query.shop-item.ts delete mode 100644 packages/api/src/modules/shop/resolvers/query.shop-payments.ts delete mode 100644 packages/api/src/modules/shop/types/index.ts delete mode 100644 packages/api/src/modules/shop/types/picture.ts delete mode 100644 packages/api/src/modules/shop/types/shop-item-answer.ts delete mode 100644 packages/api/src/modules/shop/types/shop-item-option-input.ts delete mode 100644 packages/api/src/modules/shop/types/shop-item-option.ts delete mode 100644 packages/api/src/modules/shop/types/shop-item.ts delete mode 100644 packages/api/src/modules/shop/types/shop-payment.ts delete mode 100644 packages/api/src/modules/shop/utils/index.ts delete mode 100644 packages/api/src/modules/shop/utils/permissions.ts delete mode 100644 packages/api/src/modules/shop/utils/uid.ts create mode 100644 packages/db/prisma/migrations/20241017131441_drop_shop/migration.sql diff --git a/.changeset/wild-cycles-eat.md b/.changeset/wild-cycles-eat.md new file mode 100644 index 000000000..dea09713e --- /dev/null +++ b/.changeset/wild-cycles-eat.md @@ -0,0 +1,6 @@ +--- +'@churros/api': major +'@churros/db': major +--- + +feat(shop): drop shops (shops will come back as a separate project) diff --git a/.old-app-routes/bookings/+page.gql b/.old-app-routes/bookings/+page.gql deleted file mode 100644 index d3bbe570e..000000000 --- a/.old-app-routes/bookings/+page.gql +++ /dev/null @@ -1,12 +0,0 @@ -# since we still use zeus when booking new tickets, we can't cache this query -# because houdini is not aware of the change, and serves stale data... -query PageBookings @cache(policy: NoCache) { - me { - bookings { - nodes { - id - code - } - } - } -} diff --git a/.old-app-routes/bookings/+page.svelte b/.old-app-routes/bookings/+page.svelte deleted file mode 100644 index 0d589574e..000000000 --- a/.old-app-routes/bookings/+page.svelte +++ /dev/null @@ -1,72 +0,0 @@ - - - - -
- {#if $PageBookings.data?.me} -
    - {#each $PageBookings.data.me.bookings.nodes.filter(notNull) as booking (booking.id)} -
  • - -
  • - {/each} -
- {:else} -
{ - await goto(`/bookings/${code}`); - }} - > - - Accéder à ma place - - {/if} -
- - diff --git a/.old-app-routes/bookings/[pseudoID].pdf/+server.ts b/.old-app-routes/bookings/[pseudoID].pdf/+server.ts deleted file mode 100644 index cede27506..000000000 --- a/.old-app-routes/bookings/[pseudoID].pdf/+server.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { env } from '$env/dynamic/public'; -import { redirect } from '@sveltejs/kit'; -import type { RequestHandler } from './$types'; - -export const GET: RequestHandler = ({ params: { pseudoID } }) => { - throw redirect(302, new URL(`/print-booking/${pseudoID}`, env.PUBLIC_API_URL)); -}; diff --git a/.old-app-routes/bookings/[pseudoID]/+page.server.ts b/.old-app-routes/bookings/[pseudoID]/+page.server.ts deleted file mode 100644 index 857846a1e..000000000 --- a/.old-app-routes/bookings/[pseudoID]/+page.server.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { ensureIdPrefix, hasIdPrefix, removeIdPrefix } from '$lib/typenames'; -import { loadQuery, makeMutation } from '$lib/zeus'; -import { error, redirect } from '@sveltejs/kit'; -import type { PageServerLoad } from './$types'; - -export const load: PageServerLoad = async ({ fetch, parent, params, url }) => { - if (hasIdPrefix('Registration', params.pseudoID)) { - throw redirect( - 301, - url.pathname.replace( - params.pseudoID, - removeIdPrefix('Registration', params.pseudoID).toUpperCase(), - ), - ); - } - - const id = ensureIdPrefix('Registration', params.pseudoID.toLowerCase()); - - let markedAsPaid = false; - ({ checkIfRegistrationIsPaid: markedAsPaid } = await makeMutation( - { - checkIfRegistrationIsPaid: [{ id }, true], - }, - { - fetch, - parent: async () => { - const parentData = await parent(); - return { - ...parentData, - // XXX dunno why this is needed - token: parentData.token!, - }; - }, - }, - )); - - const { registration, registrationQRCode } = await loadQuery( - { - registrationQRCode: [{ id }, { path: true, viewbox: true }], - registration: [ - { - id, - }, - { - '__typename': true, - '...on Error': { - message: true, - }, - '...on QueryRegistrationSuccess': { - data: { - createdAt: true, - paymentMethod: true, - id: true, - beneficiary: true, - beneficiaryUser: { - uid: true, - firstName: true, - lastName: true, - fullName: true, - }, - authorIsBeneficiary: true, - paid: true, - opposed: true, - cancelled: true, - verified: true, - author: { - uid: true, - firstName: true, - lastName: true, - fullName: true, - }, - authorEmail: true, - ticket: { - price: true, - basePrice: true, - name: true, - group: { - name: true, - }, - links: { - computedValue: true, - value: true, - name: true, - }, - event: { - uid: true, - title: true, - startsAt: true, - group: { uid: true }, - localID: true, - }, - }, - }, - }, - }, - ], - }, - { - fetch, - parent: async () => { - const parentData = await parent(); - return { - ...parentData, - // XXX dunno why this is needed - token: parentData.token!, - }; - }, - }, - ); - - if (registration.__typename === 'Error') throw error(400, registration.message); - - return { registration: registration.data, registrationQRCode, markedAsPaid }; -}; diff --git a/.old-app-routes/bookings/[pseudoID]/+page.svelte b/.old-app-routes/bookings/[pseudoID]/+page.svelte deleted file mode 100644 index 6f844658a..000000000 --- a/.old-app-routes/bookings/[pseudoID]/+page.svelte +++ /dev/null @@ -1,492 +0,0 @@ - - -
-

- - Ma place -
- -
-

- - {#if !paid && paymentMethod === PaymentMethod.Lydia} -
- -
- Payer {Intl.NumberFormat('fr-FR', { - style: 'currency', - currency: 'EUR', - }).format(ticket.price)} -
- - {#if serverError} - {serverError} - {/if} - {:else if !paid && paymentMethod === PaymentMethod.PayPal} - {#if !paying} - { - paying = true; - }} - >Payer {Intl.NumberFormat('fr-FR', { - style: 'currency', - currency: 'EUR', - }).format(ticket.price)} - {:else} - - {/if} - {/if} - - {#if !cancelled} -
- PDF - { - const { createGoogleWalletPass } = await $zeus.mutate({ - createGoogleWalletPass: [{ code }, true], - }); - window.location.href = createGoogleWalletPass; - }} - /> -
- {/if} - -
- {#if cancelled} -
Place
annulée
- {:else} -
- - - -

{code}

-
- {/if} -
- - {#if links} - - {/if} - -
-
-
Bénéficiaire
-
- {#if authorIsBeneficiary} - {author?.fullName ?? authorEmail} - {:else if beneficiaryUser} - {beneficiaryUser.fullName} - {:else} - {beneficiary} - {/if} -
-
Payée par
-
{author?.fullName ?? authorEmail}
-
Place
-
{ticket.name}
-
Prix
-
{ticket.basePrice}€
-
Méthode de paiement
-
{DISPLAY_PAYMENT_METHODS[paymentMethod ?? 'Other']}
-
Évènement
-
- {ticket.event.title} - {#if ticket.event.startsAt}({dateTimeFormatter.format( - new Date(ticket.event.startsAt), - )}){/if} -
-
Date de réservation
-
{formatDateTime(createdAt)}
-
-
- - {#if !cancelled && $me} -
- {#if !confirmingCancellation} - { - if (paid) confirmingCancellation = true; - else await cancelRegistration(); - }} - > - {#if paid}Libérer{:else}Annuler{/if} ma place - {:else} - -
-

Es-tu sûr·e ?

-

- Il n'est pas possible de revenir en arrière. Tu devras de nouveau prendre une place - (s'il en reste) si tu veux de nouveau en réserver une. Le remboursement n'est pas - systématique, contacte l'organisation pour savoir si tu sera remboursé·e. -

- Oui, je confirme -
-
- {/if} -
- {/if} - -
-

- Cette page vaut billet. Montre-la à l'entrée de l'évènement pour faire valloir cette - réservation. Tu peux prendre une capture d'écran et montrer celle-ci. -

-
-
- - diff --git a/.old-app-routes/groups/[uid]/shop/shop/+page.svelte b/.old-app-routes/groups/[uid]/shop/shop/+page.svelte deleted file mode 100644 index 0baff3680..000000000 --- a/.old-app-routes/groups/[uid]/shop/shop/+page.svelte +++ /dev/null @@ -1,102 +0,0 @@ - - - - -
- -

Boutique de {group.name}

-
- {#if isOnClubBoard} - - Ajouter un article - - {/if} -
-
-
- {#if shopItems.length === 0} -

Aucun article

- {/if} - {#each shopItems as shopItem} - - {/each} -
- - diff --git a/.old-app-routes/groups/[uid]/shop/shop/+page.ts b/.old-app-routes/groups/[uid]/shop/shop/+page.ts deleted file mode 100644 index e3213f369..000000000 --- a/.old-app-routes/groups/[uid]/shop/shop/+page.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { loadQuery } from '$lib/zeus'; -import type { PageLoad } from './$types'; - -export const load: PageLoad = async ({ fetch, params, parent }) => { - const { me } = await parent(); - const { group } = await loadQuery( - { - group: [ - params, - { - id: true, - uid: true, - name: true, - boardMembers: { - member: { - uid: true, - }, - }, - shopItems: [ - {}, - { - nodes: { - uid: true, - id: true, - name: true, - price: true, - max: true, - descriptionHtml: true, - stock: true, - stockLeft: true, - pictures: { - id: true, - path: true, - position: true, - }, - group: { - uid: true, - }, - visibility: true, - }, - }, - ], - }, - ], - }, - { fetch, parent }, - ); - return { group, me }; -}; diff --git a/.old-app-routes/groups/[uid]/shop/shop/[id]/+page.svelte b/.old-app-routes/groups/[uid]/shop/shop/[id]/+page.svelte deleted file mode 100644 index 0ad3507dd..000000000 --- a/.old-app-routes/groups/[uid]/shop/shop/[id]/+page.svelte +++ /dev/null @@ -1,331 +0,0 @@ - - -
-
-
-
- p.path)} /> -
-
-
- -

{shopItem.name}

- - {#if $me?.admin || group.boardMembers.find((m) => m.member.uid === $me?.uid)} - - {/if} -
-
- - {@html shopItem.descriptionHtml} -
-
-
-
-

Acheter

-

Stock: {shopItem.stock === 0 ? '+∞' : shopItem.stock}

-

Restant: {shopItem.stock === 0 ? '+∞' : shopItem.stockLeft}

-

Prix: {shopItem.price} €

- { - if (quantity < 0) quantity = 0; - if (quantity > max) quantity = max; - }} - /> - - {#if shopItem.itemOptions.length > 0} -
- {#each shopItem.itemOptions as option, i} - { - if (dropdown[i] !== 'Autre') answers[i] = dropdown[i]; - }} - /> - {#if dropdown[i] === 'Autre'} - - {/if} - {/each} -
- {/if} -
    - {#if !paying} -
      - {#each shopItem.paymentMethods as method} -
    • - payBy(method)} - > - {DISPLAY_PAYMENT_METHODS[method]} - -
    • - {:else} -
    • - Aucun moyen de paiement disponible. Contactez le bureau de {group.name}. -
    • - {/each} -
    - {:else} -
    { - paymentLoading = true; - const { paidShopPayment } = await $zeus.mutate({ - paidShopPayment: [ - { - shopPaymentId, - phone, - paymentMethod: PaymentMethod.Lydia, - }, - { - '__typename': true, - '...on Error': { message: true }, - '...on MutationPaidShopPaymentSuccess': { - data: { - __typename: true, - }, - }, - }, - ], - }); - if (paidShopPayment.__typename === 'Error') { - serverError = paidShopPayment.message; - paymentLoading = false; - return; - } else { - await goto('../orders/'); - paymentLoading = false; - toasts.add('success', 'La demande de paiement a été envoyée'); - } - }} - > - {#if choosingPaymentMethodLoading === PaymentMethod.Lydia} - - -
    - Payer {quantity * shopItem.price}€ -
    - {/if} - - {/if} -
-
-
-
- - diff --git a/.old-app-routes/groups/[uid]/shop/shop/[id]/+page.ts b/.old-app-routes/groups/[uid]/shop/shop/[id]/+page.ts deleted file mode 100644 index c91567912..000000000 --- a/.old-app-routes/groups/[uid]/shop/shop/[id]/+page.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { redirectToLogin } from '$lib/session'; -import { loadQuery } from '$lib/zeus'; -import { error } from '@sveltejs/kit'; -import type { PageLoad } from './$types'; - -export const load: PageLoad = async ({ fetch, params, parent, url }) => { - const { me } = await parent(); - if (!me) throw redirectToLogin(url.pathname); - - const data = await loadQuery( - { - group: [ - { uid: params.uid }, - { - uid: true, - name: true, - boardMembers: { - member: { - uid: true, - }, - }, - shopItem: [ - { id: params.id }, - { - id: true, - name: true, - price: true, - stock: true, - stockLeft: true, - max: true, - descriptionHtml: true, - paymentMethods: true, - pictures: { - path: true, - position: true, - }, - itemOptions: { - id: true, - name: true, - options: true, - required: true, - otherToggle: true, - }, - }, - ], - }, - ], - }, - { fetch, parent }, - ); - if (!data.group.shopItem) error(404, { message: 'Article de la boutique introuvable' }); - return data; -}; diff --git a/.old-app-routes/groups/[uid]/shop/shop/[id]/edit/+page.gql b/.old-app-routes/groups/[uid]/shop/shop/[id]/edit/+page.gql deleted file mode 100644 index 268176701..000000000 --- a/.old-app-routes/groups/[uid]/shop/shop/[id]/edit/+page.gql +++ /dev/null @@ -1,57 +0,0 @@ -query PageShopItemEdit($uid: String!, $id: LocalID!) { - group(uid: $uid) { - name - uid - shopItem(id: $id) { - id - uid - name - price - stock - max - description - startsAt - endsAt - visibility - paymentMethods - lydiaAccount { - id - name - } - group { - uid - name - pictureFile - pictureFileDark - boardMembers { - member { - uid - } - } - } - pictures { - id - path - position - } - itemOptions { - id - name - options - required - otherToggle - } - } - lydiaAccounts { - id - name - # TODO remove - group { - uid - name - pictureFile - pictureFileDark - } - } - } -} diff --git a/.old-app-routes/groups/[uid]/shop/shop/[id]/edit/+page.svelte b/.old-app-routes/groups/[uid]/shop/shop/[id]/edit/+page.svelte deleted file mode 100644 index 394024f57..000000000 --- a/.old-app-routes/groups/[uid]/shop/shop/[id]/edit/+page.svelte +++ /dev/null @@ -1,41 +0,0 @@ - - -
- -

Modifier un article de {data.group.name}

-
- - - - diff --git a/.old-app-routes/groups/[uid]/shop/shop/[id]/edit/+page.ts b/.old-app-routes/groups/[uid]/shop/shop/[id]/edit/+page.ts deleted file mode 100644 index 9936bf815..000000000 --- a/.old-app-routes/groups/[uid]/shop/shop/[id]/edit/+page.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { load_PageShopItemEdit } from '$houdini'; -import { error } from '@sveltejs/kit'; -import { get } from 'svelte/store'; - -export async function load(event) { - const { data, errors } = await load_PageShopItemEdit({ event, variables: event.params }).then( - (stores) => get(stores.PageShopItemEdit), - ); - if (!data) error(500, { message: JSON.stringify(errors) }); - if (!data.group) error(404, { message: 'Boutique introuvable' }); - if (!data.group.shopItem) error(404, { message: 'Article indisponible' }); - return data as typeof data & { - group: NonNullable<(typeof data)['group']> & { - shopItem: NonNullable<(typeof data)['group']['shopItem']>; - }; - }; -} diff --git a/.old-app-routes/groups/[uid]/shop/shop/create/+page.svelte b/.old-app-routes/groups/[uid]/shop/shop/create/+page.svelte deleted file mode 100644 index b15e3dce7..000000000 --- a/.old-app-routes/groups/[uid]/shop/shop/create/+page.svelte +++ /dev/null @@ -1,36 +0,0 @@ - - -
- -

Nouvel article de {data.shopItem.group.name}

-
- - - - diff --git a/.old-app-routes/groups/[uid]/shop/shop/create/+page.ts b/.old-app-routes/groups/[uid]/shop/shop/create/+page.ts deleted file mode 100644 index 9e47dc0d4..000000000 --- a/.old-app-routes/groups/[uid]/shop/shop/create/+page.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { redirectToLogin } from '$lib/session'; -import { Visibility, loadQuery } from '$lib/zeus.js'; -import type { PageLoad } from './$types'; - -export const load: PageLoad = async ({ fetch, params, parent, url }) => { - const { me } = await parent(); - if (!me) throw redirectToLogin(url.pathname); - - const { group, lydiaAccounts } = await loadQuery( - { - group: [ - { uid: params.uid }, - { - pictureFile: true, - pictureFileDark: true, - uid: true, - name: true, - members: { - member: { uid: true }, - }, - }, - ], - lydiaAccounts: { - id: true, - name: true, - group: { - uid: true, - name: true, - pictureFile: true, - pictureFileDark: true, - }, - }, - }, - { fetch, parent }, - ); - - return { - shopItem: { - id: '', - uid: '', - name: '', - price: 0, - stock: 0, - max: 0, - description: '', - paymentMethods: [], - lydiaAccount: undefined, - visibility: Visibility.Private, - startsAt: undefined, - endsAt: undefined, - group, - groupUid: group.uid, - itemOptions: [], - }, - lydiaAccounts, - }; -}; diff --git a/.old-app-routes/groups/[uid]/shop/shop/orders/+page.svelte b/.old-app-routes/groups/[uid]/shop/shop/orders/+page.svelte deleted file mode 100644 index b6e621de6..000000000 --- a/.old-app-routes/groups/[uid]/shop/shop/orders/+page.svelte +++ /dev/null @@ -1,87 +0,0 @@ - - - -
- -

Mes achats

-
-
- {#if shopOrders.length === 0} -

Aucun article

- {/if} - {#each shopOrders as order} - - {/each} -
- - diff --git a/.old-app-routes/groups/[uid]/shop/shop/orders/+page.ts b/.old-app-routes/groups/[uid]/shop/shop/orders/+page.ts deleted file mode 100644 index e5e7ff8c1..000000000 --- a/.old-app-routes/groups/[uid]/shop/shop/orders/+page.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { loadQuery } from '$lib/zeus'; -import type { PageLoad } from './$types'; - -export const load: PageLoad = async ({ fetch, params, parent }) => { - const { me } = await parent(); - const data = await loadQuery( - { - group: [ - { - uid: params.uid, - }, - { - shopOrders: { - id: true, - quantity: true, - paid: true, - totalPrice: true, - paymentMethod: true, - shopItem: { - uid: true, - id: true, - name: true, - price: true, - description: true, - paymentMethods: true, - visibility: true, - group: { uid: true }, - pictures: { - path: true, - }, - }, - }, - boardMembers: { - member: { - uid: true, - }, - }, - }, - ], - }, - { fetch, parent }, - ); - return { me, ...data }; -}; diff --git a/.old-app-routes/groups/[uid]/shop/shop/sales/+page.svelte b/.old-app-routes/groups/[uid]/shop/shop/sales/+page.svelte deleted file mode 100644 index 0ffa8499d..000000000 --- a/.old-app-routes/groups/[uid]/shop/shop/sales/+page.svelte +++ /dev/null @@ -1,50 +0,0 @@ - - -
- -

Gestion de la boutique

- {#if isOnClubBoard} - - Ajouter un article - - {/if} -
- -
- -
- - diff --git a/.old-app-routes/groups/[uid]/shop/shop/sales/+page.ts b/.old-app-routes/groups/[uid]/shop/shop/sales/+page.ts deleted file mode 100644 index 1fcf81ecd..000000000 --- a/.old-app-routes/groups/[uid]/shop/shop/sales/+page.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { redirectToLogin } from '$lib/session'; -import { loadQuery } from '$lib/zeus'; -import { redirect } from '@sveltejs/kit'; -import type { PageLoad } from './$types'; - -export const load: PageLoad = async ({ fetch, params, parent, url }) => { - const { me } = await parent(); - if (!me) throw redirectToLogin(url.pathname); - - const data = await loadQuery( - { - group: [ - { - uid: params.uid, - }, - { - uid: true, - boardMembers: { - member: { - uid: true, - }, - }, - shopItems: [ - {}, - { - nodes: { - uid: true, - id: true, - name: true, - price: true, - max: true, - description: true, - stock: true, - stockLeft: true, - group: { - uid: true, - name: true, - }, - }, - }, - ], - }, - ], - }, - { fetch, parent }, - ); - if (!(me.admin || data.group.boardMembers.some((member) => member.member.uid === me.uid))) - throw redirect(307, '..'); - return data; -}; diff --git a/.old-app-routes/groups/[uid]/shop/shop/sales/[itemUid]/+page.svelte b/.old-app-routes/groups/[uid]/shop/shop/sales/[itemUid]/+page.svelte deleted file mode 100644 index 6ffdab7c9..000000000 --- a/.old-app-routes/groups/[uid]/shop/shop/sales/[itemUid]/+page.svelte +++ /dev/null @@ -1,51 +0,0 @@ - - -
- -

Liste des payements pour {shopItem.name}

-
- -
- {#if shopItem.shopPayments.length === 0} -

Aucune commande ;(

- {:else} - - {/if} -
- - diff --git a/.old-app-routes/groups/[uid]/shop/shop/sales/[itemUid]/+page.ts b/.old-app-routes/groups/[uid]/shop/shop/sales/[itemUid]/+page.ts deleted file mode 100644 index 4e3f43296..000000000 --- a/.old-app-routes/groups/[uid]/shop/shop/sales/[itemUid]/+page.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { loadQuery } from '$lib/zeus'; -import { error } from '@sveltejs/kit'; -import type { PageLoad } from './$types'; - -export const load: PageLoad = async ({ fetch, params, parent }) => { - const { shopItem } = await loadQuery( - { - shopItem: [ - { - slug: params.itemUid, - }, - { - id: true, - name: true, - itemOptions: { - name: true, - options: true, - }, - shopPayments: { - id: true, - quantity: true, - paid: true, - totalPrice: true, - paymentMethod: true, - user: { - uid: true, - fullName: true, - pictureFile: true, - }, - shopItemAnswer: { - options: true, - }, - }, - }, - ], - }, - { fetch, parent }, - ); - - if (!shopItem) error(404, { message: `Article de boutique ${params.itemUid} introuvable` }); - return { shopItem }; -}; diff --git a/.old-app-routes/users/[uid]/+page.svelte b/.old-app-routes/users/[uid]/+page.svelte deleted file mode 100644 index b8ec8f822..000000000 --- a/.old-app-routes/users/[uid]/+page.svelte +++ /dev/null @@ -1,516 +0,0 @@ - - -
-
-
- {#if roleBadge} -
- {roleBadge} -
- {/if} - - {user.fullName} -
- -
-

-
- {user.firstName} - {user.lastName} - {#if user.admin} - - - - {/if} - {#if isDeveloper} - - - - {/if} - {#if user.bot} - - - - {/if} -
- -
- - {#if $me?.uid === user.uid || $me?.admin || data.user.canBeEdited} - - - - {/if} - {#if $me?.uid === user.uid} - - - - {/if} -
-

-

- @{user.uid} -

-

- {user.yearTier}A ({user.graduationYear}) · - {#if user.major} - {user.major.shortName} - {#if user.minor} - · - {user.minor.shortName} - {/if} - · - {#each user.major.schools as school} - {school.name} - {/each} - {:else}Exté - {/if} - {user.apprentice ? 'FISA' : ''} -

- -

- - {@html user.descriptionHtml} -

-
-
- {#if user.nickname} -
Surnom
-
{user.nickname}
- {/if} - {#if user.contributesTo} -
Cotisant·e
- {#if user.contributesTo.length > 0} -
- {user.contributesTo - .filter((c) => c !== undefined) - .map((c) => c?.name) - .join(', ')} -
- {:else} -
Non
- {/if} - {/if} -
Email{user.otherEmails.length > 0 ? 's' : ''}
-
- {#each [user.email, ...user.otherEmails] as email} - {email} - {/each} -
- {#if user.phone} -
Téléphone
-
- {formatPhoneNumber(user.phone)} -
- {/if} - {#if user.birthday} -
Date de naissance
-
{dateFormatter.format(user.birthday)}
- - {/if} - {#if user.address} -
Adresse
-
{user.address}
- - {/if} -
Identifiant
-
{user.uid}
-
-
-
-
- - {#if !$me?.external && $me?.uid === user.uid && ((user.pendingContributions?.length ?? 0) > 0 || (user.contributesTo?.length ?? 0) <= 0)} -
- {#each contributionOptions as option} -

Cotiser pour {option.name}

-
- - {@html option.descriptionHtml} -
- {/each} -
- -
- -

- Tu peux aussi payer par chèque ou espèces. Renseigne-toi auprès du BDE. -

-
- {/if} - - {#if user.groups.length} -
-

{user.groups.length === 1 ? 'Groupe' : 'Groupes'}

- ({ - ...group, - - role: `${rolesBadge(roles)} ${title}`, - }))} - /> -
- {:else if !$me?.external && $me?.uid === user.uid} -
-

Groupes

-

Tu n'es dans aucun groupe... 😢

- Découvre les clubs ! -
- {/if} - - {#if data.user.familyTree.users.length >= 2} -
-

Famille

- -
- -
-
- {/if} -
- - diff --git a/.old-app-routes/users/[uid]/+page.ts b/.old-app-routes/users/[uid]/+page.ts deleted file mode 100644 index cec665454..000000000 --- a/.old-app-routes/users/[uid]/+page.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { graphql, load_PageUserAreaContribute } from '$houdini'; -import { redirectToLogin } from '$lib/session'; -import { byMemberGroupTitleImportance } from '$lib/sorting'; -import { loadQuery } from '$lib/zeus'; -import type { PageLoad } from './$types'; - -graphql(` - query PageUserAreaContribute($uid: String!, $loggedIn: Boolean!) { - user(uid: $uid) @include(if: $loggedIn) { - ...AreaContribute_User - major { - schools { - studentAssociations { - ...AreaContribute_StudentAssociation - } - } - } - } - } -`); - -export const load: PageLoad = async (event) => { - const { fetch, params, parent, url } = event; - const { me } = await parent(); - if (!me) throw redirectToLogin(url.pathname); - const { user } = await loadQuery( - { - user: [params, { canBeEdited: true }], - }, - { fetch, parent }, - ); - - const data = await loadQuery( - { - contributionOptions: { - name: true, - price: true, - id: true, - descriptionHtml: true, - paysFor: { name: true, id: true, uid: true }, - offeredIn: { name: true, id: true, uid: true }, - }, - user: [ - params, - { - admin: true, - canBeEdited: true, - apprentice: true, - uid: true, - address: true, - birthday: true, - createdAt: true, - description: true, - descriptionHtml: true, - firstName: true, - graduationYear: true, - yearTier: true, - lastName: true, - fullName: true, - nickname: true, - email: true, - otherEmails: true, - phone: true, - pictureFile: true, - bot: true, - groups: { - group: { uid: true, name: true, color: true, pictureFile: true, pictureFileDark: true }, - member: { - lastName: true, - }, - title: true, - president: true, - treasurer: true, - vicePresident: true, - secretary: true, - }, - links: { name: true, value: true, computedValue: true }, - minor: { - name: true, - shortName: true, - uid: true, - }, - major: { - uid: true, - name: true, - shortName: true, - schools: { - uid: true, - name: true, - color: true, - studentAssociations: { - id: true, - name: true, - }, - }, - }, - familyTree: { - nesting: true, - users: { - uid: true, - firstName: true, - lastName: true, - fullName: true, - pictureFile: true, - graduationYear: true, - }, - }, - ...(me.uid === params.uid ? { pendingContributions: { name: true, id: true } } : {}), - ...(user.canBeEdited - ? { - contributesTo: { - name: true, - id: true, - }, - } - : {}), - articles: [ - {}, - { - edges: { - node: { - id: true, - localID: true, - title: true, - uid: true, - group: { uid: true, name: true, pictureFile: true, pictureFileDark: true }, - bodyHtml: true, - bodyPreview: true, - publishedAt: true, - links: { value: true, name: true, computedValue: true }, - visibility: true, - }, - }, - }, - ], - }, - ], - codeContributors: { - '__typename': true, - '...on QueryCodeContributorsSuccess': { - data: { uid: true }, - }, - '...on Error': { - message: true, - }, - }, - }, - { fetch, parent }, - ); - - return { - ...(await load_PageUserAreaContribute({ - event, - variables: { uid: params.uid, loggedIn: true }, - })), - ...data, - user: { - ...data.user, - groups: data.user.groups.sort(byMemberGroupTitleImportance), - }, - isDeveloper: - data.codeContributors.__typename === 'QueryCodeContributorsSuccess' - ? data.codeContributors.data.some((c) => c.uid === data.user.uid) - : false, - }; -}; diff --git a/packages/api/.graphinx.yaml b/packages/api/.graphinx.yaml index b226a0160..db55f5383 100644 --- a/packages/api/.graphinx.yaml +++ b/packages/api/.graphinx.yaml @@ -59,7 +59,6 @@ modules: - posts - events - ticketing - - shop - forms - documents - themes diff --git a/packages/api/barrelsby.config.json b/packages/api/barrelsby.config.json index 8e16b24be..1d2957a4a 100644 --- a/packages/api/barrelsby.config.json +++ b/packages/api/barrelsby.config.json @@ -66,9 +66,6 @@ "./src/modules/services/resolvers", "./src/modules/services/types", "./src/modules/services/utils", - "./src/modules/shop/resolvers", - "./src/modules/shop/types", - "./src/modules/shop/utils", "./src/modules/student-associations/resolvers", "./src/modules/student-associations/types", "./src/modules/student-associations/utils", diff --git a/packages/api/src/lib/global-id.ts b/packages/api/src/lib/global-id.ts index b85f3cf67..526bcc1dd 100644 --- a/packages/api/src/lib/global-id.ts +++ b/packages/api/src/lib/global-id.ts @@ -41,11 +41,6 @@ export const ID_PREFIXES_TO_TYPENAMES = { reac: 'Reaction', promocode: 'PromotionCode', promo: 'Promotion', - picfile: 'Picture', - shopitem: 'ShopItem', - shoppayment: 'ShopPayment', - shopitemoption: 'ShopItemOption', - shopitemanswer: 'ShopItemAnswer', form: 'Form', formsection: 'FormSection', formjump: 'FormJump', diff --git a/packages/api/src/lib/pictures.ts b/packages/api/src/lib/pictures.ts index 37f3a7fd4..351df7fb7 100644 --- a/packages/api/src/lib/pictures.ts +++ b/packages/api/src/lib/pictures.ts @@ -3,6 +3,7 @@ import { GraphQLError } from 'graphql'; import type { ImageFileExtension } from 'image-type'; import imageType from 'image-type'; import { mkdir, unlink } from 'node:fs/promises'; +// eslint-disable-next-line unicorn/import-style import { dirname, join, relative } from 'node:path'; import sharp from 'sharp'; @@ -241,14 +242,6 @@ export async function updatePicture({ break; } - case 'photos': { - await prisma.picture.update({ - where: { id: identifier }, - data: { path: relative(root, path) }, - }); - break; - } - case 'school': { await prisma.school.update({ where: { id: ensureGlobalId(identifier, 'School') }, diff --git a/packages/api/src/modules/payments/utils/lydia/pay.ts b/packages/api/src/modules/payments/utils/lydia/pay.ts index 9f5ab197b..f99b196fb 100644 --- a/packages/api/src/modules/payments/utils/lydia/pay.ts +++ b/packages/api/src/modules/payments/utils/lydia/pay.ts @@ -1,7 +1,7 @@ import { log, prisma } from '#lib'; -import type { LydiaAccount, LydiaTransaction, ShopItem, ShopPayment } from '@churros/db/prisma'; -import { GraphQLError } from 'graphql'; import { actualPrice, checkLydiaTransaction, sendLydiaPaymentRequest } from '#modules/payments'; +import type { LydiaTransaction } from '@churros/db/prisma'; +import { GraphQLError } from 'graphql'; // Get the Lydia API URL from the environment const { PUBLIC_LYDIA_API_URL } = process.env; @@ -102,66 +102,3 @@ export async function cancelLydiaTransaction(transaction: LydiaTransaction, vend }), }); } - -export async function payShopPaymentViaLydia( - phone: string, - shopPayment: ShopPayment & { - shopItem: ShopItem & { lydiaAccount: LydiaAccount | null }; - lydiaTransaction: LydiaTransaction | null; - }, -): Promise { - if (!shopPayment.shopItem.lydiaAccount) throw new Error('Lydia account not found'); - // Check if transaction was already paid for, in that case mark registration as paid - if (shopPayment.lydiaTransaction?.requestId && shopPayment.lydiaTransaction.requestUuid) { - const { paid } = await checkLydiaTransaction(shopPayment.lydiaTransaction); - if (paid) { - await log( - 'lydia', - 'fallback mark as paid', - { message: 'Transaction was already paid for, marking registration as paid' }, - shopPayment.id, - ); - await prisma.shopPayment.update({ - where: { id: shopPayment.id }, - data: { - paid: true, - }, - }); - return; - } - } - - let transaction = shopPayment.lydiaTransaction; - // Check if a lydia transaction already exists - if (!transaction) { - // Create a lydia transaction - transaction = await prisma.lydiaTransaction.create({ - data: { - shopPayment: { connect: { id: shopPayment.id } }, - phoneNumber: phone, - }, - }); - } - - // Cancel the previous transaction - if (transaction.requestId && transaction.requestUuid) { - // Cancel the previous transaction - await cancelLydiaTransaction(transaction, shopPayment.shopItem.lydiaAccount.vendorToken); - } - - const requestDetails = await sendLydiaPaymentRequest( - shopPayment.shopItem.name, - shopPayment.shopItem.price * shopPayment.quantity, - phone, - shopPayment.shopItem.lydiaAccount.vendorToken, - ); - - // Update the lydia transaction - await prisma.lydiaTransaction.update({ - where: { id: transaction.id }, - data: { - phoneNumber: phone, - ...requestDetails, - }, - }); -} diff --git a/packages/api/src/modules/shop/README.md b/packages/api/src/modules/shop/README.md deleted file mode 100644 index 2dc74c61e..000000000 --- a/packages/api/src/modules/shop/README.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -color: red ---- - -# Boutique - -Système de boutique permettant aux groupes de mettre en vente des produits. diff --git a/packages/api/src/modules/shop/icon.svg b/packages/api/src/modules/shop/icon.svg deleted file mode 100644 index 986ad4d95..000000000 --- a/packages/api/src/modules/shop/icon.svg +++ /dev/null @@ -1,6 +0,0 @@ - diff --git a/packages/api/src/modules/shop/index.ts b/packages/api/src/modules/shop/index.ts deleted file mode 100644 index d08c47cc8..000000000 --- a/packages/api/src/modules/shop/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @file generated by packages/api/scripts/generate-barrelsby-config.ts - * The order of imports matters to Pothos, so we need to hardcode the import order, - * barrelsby cannot do this, so we do it ourselves with a little bash scripting. - */ - -// organize-imports-ignore -export * from './types/index.js'; -export * from './resolvers/index.js'; - -export * from './utils/index.js'; diff --git a/packages/api/src/modules/shop/resolvers/group.shop-item.ts b/packages/api/src/modules/shop/resolvers/group.shop-item.ts deleted file mode 100644 index 5cfef19ca..000000000 --- a/packages/api/src/modules/shop/resolvers/group.shop-item.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { builder, ensureGlobalId, prisma } from '#lib'; -import { LocalID } from '#modules/global'; -import { GroupType } from '#modules/groups'; -import { ShopItemType } from '#modules/shop/types'; -import { canAccessShopItem } from '../utils/permissions.js'; - -builder.prismaObjectField(GroupType, 'shopItem', (t) => - t.prismaField({ - type: ShopItemType, - nullable: true, - description: 'Article de la boutique du groupe', - args: { - id: t.arg({ type: LocalID }), - }, - async authScopes(group, { id }, { user }) { - const item = await prisma.shopItem.findUniqueOrThrow({ - where: { - id: ensureGlobalId(id, 'ShopItem'), - groupId: group.id, - }, - }); - return canAccessShopItem(user, { ...item, group }); - }, - async resolve(query, group, { id }) { - return prisma.shopItem.findUnique({ - ...query, - where: { - id: ensureGlobalId(id, 'ShopItem'), - groupId: group.id, - }, - }); - }, - }), -); diff --git a/packages/api/src/modules/shop/resolvers/group.shop-items.ts b/packages/api/src/modules/shop/resolvers/group.shop-items.ts deleted file mode 100644 index 88aec9072..000000000 --- a/packages/api/src/modules/shop/resolvers/group.shop-items.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { builder, prisma } from '#lib'; -import { GroupType } from '#modules/groups'; -import { GraphQLError } from 'graphql'; -import { canListShopItem, ShopItemType } from '../index.js'; - -builder.prismaObjectField(GroupType, 'shopItems', (t) => - t.prismaConnection({ - type: ShopItemType, - cursor: 'id', - async resolve(query, { id: groupId }, _, { user }) { - const items = await prisma.shopItem.findMany({ - ...query, - where: { groupId }, - include: { - group: { - include: { - members: { - include: { - member: true, - }, - where: { - member: { - id: user?.id, - }, - }, - }, - studentAssociation: { - select: { - schoolId: true, - }, - }, - }, - }, - }, - orderBy: { - createdAt: 'desc', - }, - }); - - if (!items) throw new GraphQLError('No item found'); - if (user?.admin) return items; - return items.filter((item) => canListShopItem(user, item)); - }, - }), -); diff --git a/packages/api/src/modules/shop/resolvers/group.shop-orders.ts b/packages/api/src/modules/shop/resolvers/group.shop-orders.ts deleted file mode 100644 index 73a355b10..000000000 --- a/packages/api/src/modules/shop/resolvers/group.shop-orders.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { builder, prisma } from '#lib'; -import { GroupType } from '#modules/groups'; -import { ShopPaymentType } from '../index.js'; - -builder.prismaObjectField(GroupType, 'shopOrders', (t) => - t.prismaField({ - type: [ShopPaymentType], - async resolve(query, { uid: groupUid }, _, { user }) { - return prisma.shopPayment.findMany({ - ...query, - where: { - user: { - id: user?.id, - }, - shopItem: { - group: { - uid: groupUid ?? undefined, - }, - }, - }, - include: { - shopItem: { - include: { - pictures: true, - }, - }, - }, - orderBy: { - createdAt: 'desc', - }, - }); - }, - }), -); diff --git a/packages/api/src/modules/shop/resolvers/index.ts b/packages/api/src/modules/shop/resolvers/index.ts deleted file mode 100644 index 98a32025a..000000000 --- a/packages/api/src/modules/shop/resolvers/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @file Automatically generated by barrelsby. - */ - -export * from './group.shop-item.js'; -export * from './group.shop-items.js'; -export * from './group.shop-orders.js'; -export * from './mutation.delete-item-picture.js'; -export * from './mutation.delete-shop-item.js'; -export * from './mutation.delete-shop-option.js'; -export * from './mutation.paid-shop-payment.js'; -export * from './mutation.update-item-picture.js'; -export * from './mutation.upsert-shop-item.js'; -export * from './mutation.upsert-shop-options.js'; -export * from './mutation.upsert-shop-payment.js'; -export * from './query.shop-item.js'; -export * from './query.shop-payments.js'; diff --git a/packages/api/src/modules/shop/resolvers/mutation.delete-item-picture.ts b/packages/api/src/modules/shop/resolvers/mutation.delete-item-picture.ts deleted file mode 100644 index 654e556cb..000000000 --- a/packages/api/src/modules/shop/resolvers/mutation.delete-item-picture.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { builder, log, prisma, storageRoot } from '#lib'; -import { userIsOnBoardOf } from '#permissions'; -import { GraphQLError } from 'graphql'; -import { unlink } from 'node:fs/promises'; -import path from 'node:path'; - -builder.mutationField('deleteItemPicture', (t) => - t.field({ - type: 'Boolean', - args: { - itemId: t.arg.string(), - pictureId: t.arg.string(), - groupUid: t.arg.string(), - }, - authScopes: (_, { groupUid }, { user }) => - Boolean(user?.admin || userIsOnBoardOf(user, groupUid)), - async resolve(_, { itemId, pictureId, groupUid }, { user }) { - if (!(user?.admin || userIsOnBoardOf(user, groupUid))) - throw new GraphQLError('You do not have the rights to delete this picture'); - const pictureFile = await prisma.picture.findUniqueOrThrow({ - where: { id: pictureId }, - select: { path: true }, - }); - const root = storageRoot(); - if (pictureFile) await unlink(path.join(root, pictureFile.path)); - await prisma.picture.delete({ where: { id: pictureId } }); - await prisma.shopItem.update({ - where: { id: itemId }, - data: { pictures: { disconnect: { id: pictureId } } }, - }); - await log('shop', 'update', { message: `Suppression de la photo` }, itemId, user); - return true; - }, - }), -); diff --git a/packages/api/src/modules/shop/resolvers/mutation.delete-shop-item.ts b/packages/api/src/modules/shop/resolvers/mutation.delete-shop-item.ts deleted file mode 100644 index 3cbcdb45a..000000000 --- a/packages/api/src/modules/shop/resolvers/mutation.delete-shop-item.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { builder, log, prisma, storageRoot } from '#lib'; -import { userIsOnBoardOf } from '#permissions'; -import { GraphQLError } from 'graphql'; -import { unlink } from 'node:fs/promises'; -import path from 'node:path'; - -builder.mutationField('deleteShopItem', (t) => - t.field({ - type: 'Boolean', - errors: {}, - args: { - itemId: t.arg.id(), - groupUid: t.arg.string(), - }, - authScopes: (_, { groupUid }, { user }) => - Boolean(user?.admin || userIsOnBoardOf(user, groupUid)), - async resolve(_, { itemId }, { user }) { - const shopItem = await prisma.shopItem.findUniqueOrThrow({ - where: { id: itemId }, - include: { - shopPayments: true, - pictures: true, - }, - }); - - if (!shopItem) throw new GraphQLError('Item not found'); - - if (shopItem.shopPayments && shopItem.shopPayments.length > 0) - throw new GraphQLError('You cannot delete an item where someone has placed an order on'); - - //Delete all pictures of the item if there are any (let's save some Giga-Octets) - const root = storageRoot(); - for (const picture of shopItem.pictures) { - await unlink(path.join(root, picture.path)); - await prisma.picture.delete({ where: { id: picture.id } }); - } - - await prisma.shopItem.delete({ - where: { id: itemId }, - }); - - await log( - 'group', - 'delete', - { message: `Suppression de l'article ${shopItem.name} par ${user?.uid}` }, - itemId, - user, - ); - - return true; - }, - }), -); diff --git a/packages/api/src/modules/shop/resolvers/mutation.delete-shop-option.ts b/packages/api/src/modules/shop/resolvers/mutation.delete-shop-option.ts deleted file mode 100644 index dd71913d2..000000000 --- a/packages/api/src/modules/shop/resolvers/mutation.delete-shop-option.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { builder, prisma } from '#lib'; -import { userIsOnBoardOf } from '#permissions'; - -builder.mutationField('deleteShopOption', (t) => - t.field({ - type: 'Boolean', - args: { - optionIds: t.arg.stringList(), - }, - async authScopes(_, { optionIds }, { user }) { - const option = await prisma.shopItemOption.findUnique({ - where: { id: optionIds[0] }, - select: { shopItem: { select: { group: { select: { uid: true } } } } }, - }); - if (!option) throw new Error('Shop option not found'); - return Boolean(user?.admin || userIsOnBoardOf(user, option.shopItem.group.uid)); - }, - async resolve(_, { optionIds }) { - for (const id of optionIds) { - const deletedOption = await prisma.shopItemOption.delete({ where: { id } }); - if (!deletedOption) throw new Error('Failed to delete shop option'); - } - return true; - }, - }), -); diff --git a/packages/api/src/modules/shop/resolvers/mutation.paid-shop-payment.ts b/packages/api/src/modules/shop/resolvers/mutation.paid-shop-payment.ts deleted file mode 100644 index de3a8fe2f..000000000 --- a/packages/api/src/modules/shop/resolvers/mutation.paid-shop-payment.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { builder, log, prisma } from '#lib'; -import { PaymentMethodEnum, payShopPaymentViaLydia } from '#modules/payments'; -import { userIsOnBoardOf } from '#permissions'; -import { - PaymentMethod as PaymentMethodPrisma, - type LydiaAccount, - type LydiaTransaction, - type ShopItem, - type ShopPayment, -} from '@churros/db/prisma'; -import { GraphQLError } from 'graphql'; -import { ShopPaymentType } from '../index.js'; - -builder.mutationField('paidShopPayment', (t) => - t.prismaField({ - type: ShopPaymentType, - errors: {}, - args: { - shopPaymentId: t.arg.id(), - paymentMethod: t.arg({ type: PaymentMethodEnum, required: false }), - phone: t.arg.string({ required: false }), - }, - async authScopes(_, { shopPaymentId }, { user }) { - if (!user) return false; - const shopPayment = await prisma.shopPayment.findUnique({ - where: { id: shopPaymentId }, - include: { - shopItem: { - include: { - group: true, - lydiaAccount: true, - }, - }, - }, - }); - - if (!shopPayment) throw new GraphQLError("La commande n'existe pas"); - - return true; - }, - async resolve(query, _, { shopPaymentId, paymentMethod, phone }, { user }) { - if (!user) throw new GraphQLError('User not found'); - - const shopPayment = await prisma.shopPayment.findUnique({ - where: { id: shopPaymentId }, - include: { - shopItem: { - include: { group: true, lydiaAccount: true, shopPayments: { where: { paid: true } } }, - }, - lydiaTransaction: true, - }, - }); - - if (!shopPayment) throw new GraphQLError('Shop payment not found'); - if (user?.admin || userIsOnBoardOf(user, shopPayment.shopItem.group.uid)) { - await prisma.shopPayment.update({ - where: { id: shopPaymentId }, - data: { - paid: !shopPayment.paid, - }, - }); - return shopPayment; - } - if (!paymentMethod) throw new GraphQLError('Payment method not found'); - - const stockLeft = - shopPayment.shopItem.stock === 0 - ? Number.POSITIVE_INFINITY - : shopPayment.shopItem.stock - - shopPayment.shopItem.shopPayments.reduce((acc, curr) => acc + curr.quantity, 0); - - const userLeft = - shopPayment.shopItem.max === 0 - ? Number.POSITIVE_INFINITY - : shopPayment.shopItem.max - - shopPayment.shopItem.shopPayments.reduce( - (acc, curr) => acc + (curr.userId === user.uid ? curr.quantity : 0), - 0, - ); - - if (shopPayment.quantity > stockLeft) throw new GraphQLError('Not enough stock'); - else if (shopPayment.quantity > userLeft) throw new GraphQLError('Too much quantity'); - - // Process payment - await pay({ shopPayment, phone: phone ?? '' }); - await log( - 'shop payment', - 'update', - { - message: `${user.uid} tried to pay for shop payment ${shopPaymentId} with ${paymentMethod}, current state is ${shopPayment.paid}`, - }, - shopPaymentId, - user, - ); - - return prisma.shopPayment.update({ - ...query, - where: { id: shopPaymentId }, - data: { - paymentMethod, - }, - }); - }, - }), -); - -async function pay({ - shopPayment, - phone, -}: { - shopPayment: ShopPayment & { - shopItem: ShopItem & { lydiaAccount: LydiaAccount | null }; - lydiaTransaction: LydiaTransaction | null; - }; - phone: string; -}): Promise { - switch (shopPayment.paymentMethod) { - case PaymentMethodPrisma.Lydia: { - if (!phone) throw new GraphQLError('Phone number is required'); - await payShopPaymentViaLydia(phone, shopPayment); - return ''; - } - default: { - throw new GraphQLError('Payment method not supported'); - } - } -} diff --git a/packages/api/src/modules/shop/resolvers/mutation.update-item-picture.ts b/packages/api/src/modules/shop/resolvers/mutation.update-item-picture.ts deleted file mode 100644 index 753cbd971..000000000 --- a/packages/api/src/modules/shop/resolvers/mutation.update-item-picture.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { builder, log, prisma, updatePicture } from '#lib'; -import { userIsOnBoardOf } from '#permissions'; -import { GraphQLError } from 'graphql'; -import { PictureType } from '../index.js'; - -builder.mutationField('updateItemPicture', (t) => - t.field({ - type: PictureType, - args: { - itemId: t.arg.string(), - groupUid: t.arg.string(), - file: t.arg({ type: 'File' }), - }, - authScopes: (_, { groupUid }, { user }) => - Boolean(user?.admin || user?.groups.some(({ group }) => group.uid === groupUid)), - async resolve(_, { itemId, file, groupUid }, { user }) { - if (!(user?.admin || userIsOnBoardOf(user, groupUid))) - throw new GraphQLError('You do not have the rights to update this picture'); - await log('shop', 'update', { message: `Updated item ${itemId} pictures` }, itemId, user); - let picture = await prisma.picture.create({ - data: { path: '' }, - }); - await updatePicture({ - resource: 'photos', - folder: 'photos', - extension: 'png', - file: file, - identifier: picture.id, - }); - - await prisma.shopItem.update({ - where: { id: itemId }, - data: { - pictures: { - connect: { - id: picture.id, - }, - }, - }, - }); - picture = await prisma.picture.findFirstOrThrow({ - where: { - id: picture.id, - }, - }); - return picture; - }, - }), -); diff --git a/packages/api/src/modules/shop/resolvers/mutation.upsert-shop-item.ts b/packages/api/src/modules/shop/resolvers/mutation.upsert-shop-item.ts deleted file mode 100644 index c67a5b403..000000000 --- a/packages/api/src/modules/shop/resolvers/mutation.upsert-shop-item.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { builder, log, prisma } from '#lib'; -import { DateTimeScalar, VisibilityEnum } from '#modules/global'; -import { PaymentMethodEnum } from '#modules/payments'; -import { onBoard } from '#permissions'; -import { ShopItemType, createUid } from '../index.js'; - -builder.mutationField('upsertShopItem', (t) => - t.prismaField({ - type: ShopItemType, - errors: {}, - args: { - id: t.arg.id({ required: false }), - name: t.arg.string(), - price: t.arg.float(), - stock: t.arg.int(), - max: t.arg.int(), - description: t.arg.string(), - paymentMethods: t.arg({ type: [PaymentMethodEnum] }), - startsAt: t.arg({ type: DateTimeScalar, required: false }), - endsAt: t.arg({ type: DateTimeScalar, required: false }), - groupUid: t.arg.string(), - visibility: t.arg({ type: VisibilityEnum }), - lydiaAccounId: t.arg.string({ required: false }), - }, - - async authScopes(_, { groupUid }, { user }) { - if (!user) return false; - if (user.admin) return true; - - const group = await prisma.group.findFirst({ - where: { - uid: groupUid, - }, - include: { - members: { - include: { - member: true, - }, - where: { - member: { - id: user.id, - }, - }, - }, - }, - }); - - if (!group) return false; - - if (!onBoard(group.members[0])) return false; - - return true; - }, - async resolve( - query, - _, - { - id, - name, - price, - stock, - max, - description, - startsAt, - endsAt, - groupUid, - visibility, - lydiaAccounId, - paymentMethods, - }, - { user }, - ) { - const group = await prisma.group.findUniqueOrThrow({ where: { uid: groupUid } }); - const shopItem = await prisma.shopItem.upsert({ - ...query, - where: { id: id ?? '' }, - create: { - slug: await createUid({ title: name, groupId: group.id }), - name, - price, - stock, - max, - description, - startsAt, - endsAt, - group: { connect: { uid: groupUid } }, - lydiaAccount: lydiaAccounId ? { connect: { id: lydiaAccounId } } : undefined, - allowedPaymentMethods: { - set: paymentMethods || [], - }, - visibility, - }, - update: { - name, - price, - stock, - max, - description, - startsAt, - endsAt, - group: { connect: { uid: groupUid } }, - lydiaAccount: lydiaAccounId ? { connect: { id: lydiaAccounId } } : { disconnect: true }, - allowedPaymentMethods: { - set: paymentMethods || [], - }, - visibility, - }, - }); - - await log( - 'shop', - id ? 'update' : 'create', - { message: `Service ${shopItem.id} created: ${shopItem.name}` }, - shopItem.id, - user, - ); - - return shopItem; - }, - }), -); diff --git a/packages/api/src/modules/shop/resolvers/mutation.upsert-shop-options.ts b/packages/api/src/modules/shop/resolvers/mutation.upsert-shop-options.ts deleted file mode 100644 index 25896f08a..000000000 --- a/packages/api/src/modules/shop/resolvers/mutation.upsert-shop-options.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { builder, prisma } from '#lib'; -import { userIsOnBoardOf } from '#permissions'; -import { GraphQLError } from 'graphql'; -import { ShopItemOptionInput } from '../index.js'; - -builder.mutationField('upsertShopOptions', (t) => - t.field({ - type: 'Boolean', - args: { - shopItemId: t.arg.string(), - itemOptions: t.arg({ type: [ShopItemOptionInput] }), - }, - async authScopes(_, { shopItemId }, { user }) { - const shopItem = await prisma.shopItem.findUnique({ - where: { id: shopItemId }, - select: { group: { select: { uid: true } } }, - }); - if (!shopItem) throw new Error('Shop item not found'); - return Boolean(user?.admin || userIsOnBoardOf(user, shopItem.group.uid)); - }, - async resolve(_, { shopItemId, itemOptions }) { - for (const itemOption of itemOptions) { - let Option; - if (itemOption.id) { - Option = await prisma.shopItemOption.update({ - where: { id: itemOption.id }, - data: { - name: itemOption.name, - options: itemOption.options, - required: itemOption.required, - otherToggle: itemOption.otherToggle, - }, - }); - if (!Option) throw new GraphQLError('Failed to update shop item option'); - } else { - Option = await prisma.shopItemOption.create({ - data: { - name: itemOption.name, - options: itemOption.options, - shopItem: { connect: { id: shopItemId } }, - required: itemOption.required, - otherToggle: itemOption.otherToggle, - }, - }); - if (!Option) throw new GraphQLError('Failed to create shop item option'); - } - } - return true; - }, - }), -); diff --git a/packages/api/src/modules/shop/resolvers/mutation.upsert-shop-payment.ts b/packages/api/src/modules/shop/resolvers/mutation.upsert-shop-payment.ts deleted file mode 100644 index 77ebb8301..000000000 --- a/packages/api/src/modules/shop/resolvers/mutation.upsert-shop-payment.ts +++ /dev/null @@ -1,185 +0,0 @@ -import { builder, log, prisma } from '#lib'; -import { onBoard } from '#permissions'; -import { PaymentMethod as PaymentMethodPrisma, Visibility } from '@churros/db/prisma'; -import { GraphQLError } from 'graphql'; -import { ShopPaymentType } from '../index.js'; - -builder.mutationField('upsertShopPayment', (t) => - t.prismaField({ - type: ShopPaymentType, - errors: {}, - args: { - id: t.arg.id({ required: false }), - userUid: t.arg.string({ required: true }), - shopItemId: t.arg.string({ required: true }), - quantity: t.arg.int({ required: true }), - paymentMethod: t.arg.string({ required: false }), - phone: t.arg.string({ required: false }), - answers: t.arg.stringList({ required: true }), - }, - async authScopes(_, { shopItemId }, { user }) { - if (!user) return false; - if (user.admin) return true; - const shopItem = await prisma.shopItem.findUniqueOrThrow({ - where: { id: shopItemId }, - include: { - group: { - include: { - members: { - include: { - member: true, - }, - where: { - member: { - id: user.id, - }, - }, - }, - studentAssociation: { - include: { - school: true, - }, - }, - }, - }, - }, - }); - - switch (shopItem.visibility) { - case Visibility.Private: { - if (!onBoard(shopItem.group.members[0])) return false; - - break; - } - - case Visibility.Public: - case Visibility.Unlisted: { - break; - } - - case Visibility.GroupRestricted: { - if (shopItem.group.members.length > 0) break; - - return false; - } - - case Visibility.SchoolRestricted: { - if (shopItem.group.studentAssociation?.school.uid === user.schoolUid) break; - - return false; - } - - default: { - throw new GraphQLError('Something went wrong'); - } - } - - return true; - }, - async resolve( - query, - _, - { id, userUid, shopItemId, quantity, paymentMethod, answers }, - { user }, - ) { - const shopItem = await prisma.shopItem.findUniqueOrThrow({ - where: { id: shopItemId }, - include: { - group: true, - lydiaAccount: true, - shopPayments: { - where: { - paid: true, - }, - }, - }, - }); - - if (quantity === 0) throw new GraphQLError("You can't buy 0 of something"); - - const stockLeft = - shopItem.stock === 0 - ? Number.POSITIVE_INFINITY - : shopItem.stock - shopItem.shopPayments.reduce((acc, curr) => acc + curr.quantity, 0); - - const userLeft = - shopItem.max - - shopItem.shopPayments.reduce( - (acc, curr) => acc + (curr.userId === userUid ? curr.quantity : 0), - 0, - ); - - if (stockLeft < quantity && shopItem.stock != 0) throw new GraphQLError('Not enough stock'); - else if (userLeft < quantity && shopItem.stock != 0) - throw new GraphQLError('Too much quantity'); - - const shopOptions = await prisma.shopItemOption.findMany({ - where: { shopItemId }, - select: { - options: true, - required: true, - otherToggle: true, - }, - }); - - for (const [i, option] of Object.entries(shopOptions)) { - if (option.required && answers[Number.parseInt(i)] === '') - throw new GraphQLError('Un champ requis est manquant'); - - if ( - !option.otherToggle && - !option.options.includes(answers[Number.parseInt(i)] as string) - ) { - throw new GraphQLError( - "Petit malin, tu n'as pas le droit d'inventer ta propre réponse ici", - ); - } - } - - if (answers.some((answer) => answer.length > 255)) throw new GraphQLError('Texte trop long'); - - const shopPayment = await prisma.shopPayment.upsert({ - ...query, - where: { id: id ?? '' }, - create: { - user: { connect: { uid: userUid } }, - shopItem: { connect: { id: shopItem.id } }, - quantity, - totalPrice: shopItem.price * quantity, - paymentMethod: paymentMethod as PaymentMethodPrisma, - paid: shopItem.price === 0, - }, - update: { - user: { connect: { uid: userUid } }, - shopItem: { connect: { id: shopItem.id } }, - quantity, - totalPrice: shopItem.price * quantity, - paymentMethod: paymentMethod as PaymentMethodPrisma, - }, - include: { - shopItem: { - include: { - lydiaAccount: true, - }, - }, - lydiaTransaction: true, - }, - }); - await log( - 'shop payment', - 'create', - { message: `${shopItem.name} (x${quantity}) for ${userUid}` }, - shopPayment.id, - user, - ); - await prisma.shopItemAnswer.create({ - data: { - shopPayment: { connect: { id: shopPayment.id } }, - option: answers, - }, - }); - - return shopPayment; - }, - }), -); diff --git a/packages/api/src/modules/shop/resolvers/query.shop-item.ts b/packages/api/src/modules/shop/resolvers/query.shop-item.ts deleted file mode 100644 index 64c2b1527..000000000 --- a/packages/api/src/modules/shop/resolvers/query.shop-item.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { builder, prisma } from '#lib'; -import { userIsOnBoardOf } from '#permissions'; -import { Visibility } from '@churros/db/prisma'; -import { GraphQLError } from 'graphql'; -import { ShopItemType } from '../index.js'; - -builder.queryField('shopItem', (t) => - t.prismaField({ - type: ShopItemType, - args: { - slug: t.arg.string(), - }, - async resolve(query, _, { slug }, { user }) { - const item = await prisma.shopItem.findFirst({ - ...query, - where: { slug }, - include: { - group: { - include: { - members: { - include: { - member: true, - }, - where: { - member: { - id: user?.id, - }, - }, - }, - studentAssociation: { - select: { - schoolId: true, - }, - }, - }, - }, - }, - }); - - if (!item) throw new GraphQLError('Item not found'); - if (user?.admin) return item; - if (userIsOnBoardOf(user, item.group.uid)) return item; - // Switch case - switch (item.visibility) { - case Visibility.Private: { - if (userIsOnBoardOf(user, item.group.uid)) return item; - - throw new GraphQLError('Not allowed to view item'); - } - - case Visibility.Public: { - return item; - } - - case Visibility.Unlisted: { - return item; - } - - case Visibility.SchoolRestricted: { - if ( - user?.major?.schools.some( - (school) => item.group.studentAssociation.schoolId === school.id, - ) - ) - return item; - throw new GraphQLError('Not allowed to view item'); - } - case Visibility.GroupRestricted: { - if (user?.groups.some((s) => s.group.id === item.groupId)) return item; - - throw new GraphQLError('Not allowed to view item'); - } - - default: { - throw new GraphQLError('Something went wrong'); - } - } - }, - }), -); diff --git a/packages/api/src/modules/shop/resolvers/query.shop-payments.ts b/packages/api/src/modules/shop/resolvers/query.shop-payments.ts deleted file mode 100644 index 6278c6bd7..000000000 --- a/packages/api/src/modules/shop/resolvers/query.shop-payments.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { builder, prisma } from '#lib'; -import { onBoard } from '#permissions'; -import { ShopPaymentType } from '../index.js'; - -// TODO turn into prismaConnection -builder.queryField('shopPayments', (t) => - t.prismaField({ - type: [ShopPaymentType], - args: { - item: t.arg.id(), - }, - async authScopes(_, { item: shopItemId }, { user }) { - if (!user) return false; - if (user.admin) return true; - - const shopItem = await prisma.shopItem.findUniqueOrThrow({ - where: { id: shopItemId }, - include: { - group: { - include: { - members: { - include: { - member: true, - }, - where: { - member: { - id: user.id, - }, - }, - }, - }, - }, - }, - }); - - if (!shopItem) return false; - - if (!onBoard(shopItem.group.members[0])) return false; - - return true; - }, - async resolve(query, _, { item }) { - return prisma.shopPayment.findMany({ - ...query, - where: { - shopItem: { - id: item, - }, - }, - include: { - user: true, - }, - orderBy: { - createdAt: 'desc', - }, - }); - }, - }), -); diff --git a/packages/api/src/modules/shop/types/index.ts b/packages/api/src/modules/shop/types/index.ts deleted file mode 100644 index 5c3c46486..000000000 --- a/packages/api/src/modules/shop/types/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * @file Automatically generated by barrelsby. - */ - -export * from './picture.js'; -export * from './shop-item-answer.js'; -export * from './shop-item-option-input.js'; -export * from './shop-item-option.js'; -export * from './shop-item.js'; -export * from './shop-payment.js'; diff --git a/packages/api/src/modules/shop/types/picture.ts b/packages/api/src/modules/shop/types/picture.ts deleted file mode 100644 index 65c23c50f..000000000 --- a/packages/api/src/modules/shop/types/picture.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { builder } from '#lib'; - -export const PictureType = builder.prismaObject('Picture', { - fields: (t) => ({ - id: t.exposeID('id'), - path: t.exposeString('path'), - position: t.exposeInt('position'), - }), -}); diff --git a/packages/api/src/modules/shop/types/shop-item-answer.ts b/packages/api/src/modules/shop/types/shop-item-answer.ts deleted file mode 100644 index 0bce804e5..000000000 --- a/packages/api/src/modules/shop/types/shop-item-answer.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { builder } from '#lib'; - -export const ShopItemAnswerType = builder.prismaObject('ShopItemAnswer', { - fields: (t) => ({ - id: t.exposeID('id'), - shopPaymentId: t.exposeString('shopPaymentId'), - options: t.exposeStringList('option'), - shopPayment: t.relation('shopPayment'), - }), -}); diff --git a/packages/api/src/modules/shop/types/shop-item-option-input.ts b/packages/api/src/modules/shop/types/shop-item-option-input.ts deleted file mode 100644 index 0a2c8a07e..000000000 --- a/packages/api/src/modules/shop/types/shop-item-option-input.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { builder } from '#lib'; - -export const ShopItemOptionInput = builder.inputType('ShopItemOptionInput', { - fields: (t) => ({ - id: t.string(), - name: t.string(), - options: t.stringList(), - required: t.boolean(), - otherToggle: t.boolean(), - }), -}); diff --git a/packages/api/src/modules/shop/types/shop-item-option.ts b/packages/api/src/modules/shop/types/shop-item-option.ts deleted file mode 100644 index 1c0e763da..000000000 --- a/packages/api/src/modules/shop/types/shop-item-option.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { builder } from '#lib'; - -export const ShopItemOptionType = builder.prismaObject('ShopItemOption', { - fields: (t) => ({ - id: t.exposeID('id'), - name: t.exposeString('name'), - shopItem: t.relation('shopItem'), - options: t.exposeStringList('options'), - required: t.exposeBoolean('required'), - otherToggle: t.exposeBoolean('otherToggle'), - }), -}); diff --git a/packages/api/src/modules/shop/types/shop-item.ts b/packages/api/src/modules/shop/types/shop-item.ts deleted file mode 100644 index c8b8a69c7..000000000 --- a/packages/api/src/modules/shop/types/shop-item.ts +++ /dev/null @@ -1,144 +0,0 @@ -import { builder, prisma, toHtml } from '#lib'; -import { DateTimeScalar, VisibilityEnum } from '#modules/global'; -import { PaymentMethodEnum } from '#modules/payments'; -import { onBoard } from '#permissions'; -import { Visibility } from '@churros/db/prisma'; -import { GraphQLError } from 'graphql'; - -export const ShopItemType = builder.prismaNode('ShopItem', { - id: { field: 'id' }, - fields: (t) => ({ - uid: t.exposeString('slug', { - deprecationReason: 'Use `slug` instead. This field was never universally unique.', - }), - slug: t.exposeString('slug', { - description: 'Un nom lisible sans espaces, adaptés pour des URLs.', - }), - name: t.exposeString('name'), - description: t.exposeString('description'), - descriptionHtml: t.string({ - resolve: async ({ description }) => toHtml(description), - }), - price: t.exposeFloat('price'), - stock: t.exposeInt('stock'), - max: t.exposeInt('max'), - startsAt: t.expose('startsAt', { type: DateTimeScalar, nullable: true }), - endsAt: t.expose('endsAt', { type: DateTimeScalar, nullable: true }), - group: t.relation('group'), - createdAt: t.expose('createdAt', { type: DateTimeScalar }), - updatedAt: t.expose('updatedAt', { type: DateTimeScalar }), - pictures: t.relation('pictures'), - shopPayments: t.relation('shopPayments'), - paymentMethods: t.expose('allowedPaymentMethods', { type: [PaymentMethodEnum] }), - visibility: t.expose('visibility', { type: VisibilityEnum }), - lydiaAccount: t.relation('lydiaAccount', { nullable: true }), - stockLeft: t.field({ - type: 'Int', - async resolve({ id }) { - const item = await prisma.shopItem.findUnique({ - where: { id }, - include: { shopPayments: { where: { paid: true } } }, - }); - if (!item) throw new GraphQLError('Item not found'); - - const stockLeft = - item.stock === 0 - ? -1 - : item.stock - item.shopPayments.reduce((acc, payment) => acc + payment.quantity, 0); - - return stockLeft; - }, - }), - itemOptions: t.relation('itemOptions'), - }), -}); - -export interface VisibilityQuery { - OR?: Array<{ - visibility: Visibility; - }>; - visibility?: Visibility; -} - -export async function visibleShopPrismaQuery( - groupUid: string, - user: { id: string; schoolUid: string | null }, -) { - const group = await prisma.group.findFirst({ - where: { - uid: groupUid, - }, - include: { - members: { - include: { - member: true, - }, - where: { - member: { - id: user.id, - }, - }, - }, - studentAssociation: { - include: { - school: true, - }, - }, - }, - }); - // If user is part of the board set visibility to board visibility - if (onBoard(group?.members[0])) { - return { - OR: [ - { - visibility: Visibility.Public, - }, - { - visibility: Visibility.Private, - }, - { - visibility: Visibility.GroupRestricted, - }, - { - visibility: Visibility.SchoolRestricted, - }, - { - visibility: Visibility.Unlisted, - }, - ], - }; - } - - if (group?.members.length) { - return { - OR: [ - { - visibility: Visibility.Public, - }, - { - visibility: Visibility.GroupRestricted, - }, - { - visibility: Visibility.SchoolRestricted, - }, - ], - }; - } - - if (group?.studentAssociation?.school?.uid === user.schoolUid) { - return { - OR: [ - { - visibility: Visibility.Public, - }, - { - visibility: Visibility.SchoolRestricted, - }, - ], - }; - } - - return { - visibility: Visibility.Public, - }; -} diff --git a/packages/api/src/modules/shop/types/shop-payment.ts b/packages/api/src/modules/shop/types/shop-payment.ts deleted file mode 100644 index 5ed5292ae..000000000 --- a/packages/api/src/modules/shop/types/shop-payment.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { builder } from '#lib'; -import { DateTimeScalar } from '#modules/global'; -import { PaymentMethodEnum } from '#modules/payments'; - -export const ShopPaymentType = builder.prismaObject('ShopPayment', { - fields: (t) => ({ - id: t.exposeID('id'), - user: t.relation('user'), - paid: t.exposeBoolean('paid'), - quantity: t.exposeInt('quantity'), - totalPrice: t.exposeFloat('totalPrice'), - shopItem: t.relation('shopItem'), - paymentMethod: t.expose('paymentMethod', { type: PaymentMethodEnum }), - createdAt: t.expose('createdAt', { type: DateTimeScalar }), - updatedAt: t.expose('updatedAt', { type: DateTimeScalar }), - shopItemAnswer: t.relation('shopItemAnswer', { nullable: true }), - }), -}); diff --git a/packages/api/src/modules/shop/utils/index.ts b/packages/api/src/modules/shop/utils/index.ts deleted file mode 100644 index 6c658907a..000000000 --- a/packages/api/src/modules/shop/utils/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -/** - * @file Automatically generated by barrelsby. - */ - -export * from './permissions.js'; -export * from './uid.js'; diff --git a/packages/api/src/modules/shop/utils/permissions.ts b/packages/api/src/modules/shop/utils/permissions.ts deleted file mode 100644 index cefe9c405..000000000 --- a/packages/api/src/modules/shop/utils/permissions.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { Context } from '#lib'; -import { userIsOnBoardOf } from '#permissions'; -import { Visibility, type Group, type ShopItem } from '@churros/db/prisma'; - -export function canAccessShopItem( - user: Context['user'], - item: ShopItem & { group: Group & { studentAssociation: { schoolId: string } } }, -): boolean { - if (user?.admin) return true; - if (userIsOnBoardOf(user, item.group.uid)) return true; - switch (item.visibility) { - case Visibility.Public: { - return true; - } - case Visibility.Unlisted: { - return true; - } - - case Visibility.SchoolRestricted: { - return Boolean( - user?.major?.schools.some((school) => item.group.studentAssociation.schoolId === school.id), - ); - } - - case Visibility.GroupRestricted: { - return Boolean(user?.groups.some((s) => s.group.id === item.groupId)); - } - case Visibility.Private: { - return Boolean(userIsOnBoardOf(user, item.group.uid)); - } - - default: { - return false; - } - } -} - -export function canListShopItem( - user: Context['user'], - item: ShopItem & { group: Group & { studentAssociation: { schoolId: string } } }, -): boolean { - if (userIsOnBoardOf(user, item.group.uid)) return true; - return item.visibility !== Visibility.Unlisted && canAccessShopItem(user, item); -} diff --git a/packages/api/src/modules/shop/utils/uid.ts b/packages/api/src/modules/shop/utils/uid.ts deleted file mode 100644 index ab7e89a7c..000000000 --- a/packages/api/src/modules/shop/utils/uid.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { prisma } from '#lib'; -import dichotomid from 'dichotomid'; -import slug from 'slug'; - -export async function createUid({ title, groupId }: { title: string; groupId: string }) { - const base = slug(title); - const n = await dichotomid( - async (n) => - !(await prisma.shopItem.findUnique({ - where: { groupId_slug: { groupId, slug: `${base}${n > 1 ? `-${n}` : ''}` } }, - })), - ); - return `${base}${n > 1 ? `-${n}` : ''}`; -} diff --git a/packages/api/src/schema.ts b/packages/api/src/schema.ts index 1f7d44b2b..6d9e21541 100755 --- a/packages/api/src/schema.ts +++ b/packages/api/src/schema.ts @@ -28,7 +28,6 @@ import '#modules/reactions'; import '#modules/schools'; import '#modules/search'; import '#modules/services'; -import '#modules/shop'; import '#modules/student-associations'; import '#modules/themes'; import '#modules/ticketing'; diff --git a/packages/api/src/server/lydia.ts b/packages/api/src/server/lydia.ts index a26d48bc2..2700546f3 100644 --- a/packages/api/src/server/lydia.ts +++ b/packages/api/src/server/lydia.ts @@ -134,16 +134,6 @@ lydiaWebhook.post('/lydia-webhook', upload.none(), async (req: Request, res: Res }, }, }, - shopPayment: { - select: { - user: true, - shopItem: { - select: { - name: true, - }, - }, - }, - }, }, }); if (txn.registration?.author) { @@ -167,16 +157,6 @@ lydiaWebhook.post('/lydia-webhook', upload.none(), async (req: Request, res: Res group: undefined, }, }); - } else if (txn.shopPayment?.user) { - await notify([txn.shopPayment.user], { - title: 'Articles payés', - body: `Achat de ${txn.shopPayment.shopItem.name} confirmé`, - data: { - channel: 'Other', - goto: txn.paidCallback ?? '/', - group: undefined, - }, - }); } return res.status(200).send('OK'); } diff --git a/packages/app/schema.graphql b/packages/app/schema.graphql index 414c794c8..2c6ebe3cf 100644 --- a/packages/app/schema.graphql +++ b/packages/app/schema.graphql @@ -1722,12 +1722,6 @@ type Group implements Node & Pictured { secretaries: [GroupMember!]! selfJoinable: Boolean! services: [Service!]! - """ - Article de la boutique du groupe - """ - shopItem(id: LocalID!): ShopItem - shopItems(after: String, before: String, first: Int, last: Int): GroupShopItemsConnection! - shopOrders: [ShopPayment!]! shortDescription: String! studentAssociation: StudentAssociation! treasurers: [GroupMember!]! @@ -1853,17 +1847,6 @@ type GroupSearchResult { similarity: Float! } -type GroupShopItemsConnection { - edges: [GroupShopItemsConnectionEdge!]! - nodes: [ShopItem!]! - pageInfo: PageInfo! -} - -type GroupShopItemsConnectionEdge { - cursor: String! - node: ShopItem! -} - enum GroupType { Association Club @@ -2377,7 +2360,6 @@ type Mutation @rateLimit(limit: 1200, duration: 600) { deleteGroupMember(group: UID!, user: UID!): MutationDeleteGroupMemberResult! deleteGroupPicture(dark: Boolean!, uid: String!): Boolean! @deprecated(reason: "Use setPicture instead") - deleteItemPicture(groupUid: String!, itemId: String!, pictureId: String!): Boolean! """ Supprimer un lien existant """ @@ -2416,8 +2398,6 @@ type Mutation @rateLimit(limit: 1200, duration: 600) { Supprime un service """ deleteService(id: LocalID!): MutationDeleteServiceResult! - deleteShopItem(groupUid: String!, itemId: ID!): MutationDeleteShopItemResult! - deleteShopOption(optionIds: [String!]!): Boolean! deleteTicket( """ Supprimer le billet même s'il existe des réservations @@ -2478,11 +2458,6 @@ type Mutation @rateLimit(limit: 1200, duration: 600) { ): MutationMarkContributionAsPaidResult! mergeDocuments(from: [ID!]!, into: ID!): Document! opposeRegistration(id: ID!): MutationOpposeRegistrationResult! - paidShopPayment( - paymentMethod: PaymentMethod - phone: String - shopPaymentId: ID! - ): MutationPaidShopPaymentResult! payBooking( """ Montant que l'on souhaite payer. Par défaut, le prix du billet. Peut être supérieur si l'on souhaite payer plus @@ -2858,7 +2833,6 @@ type Mutation @rateLimit(limit: 1200, duration: 600) { Mettre à jour le profil d'un groupe """ updateGroupProfile(profile: GroupProfileInput!, uid: UID!): MutationUpdateGroupProfileResult! - updateItemPicture(file: File!, groupUid: String!, itemId: String!): Picture! """ Mettre à jour un lien existant """ @@ -3128,30 +3102,6 @@ type Mutation @rateLimit(limit: 1200, duration: 600) { Create or update a service """ upsertServiceV2(id: LocalID, input: ServiceInput!): MutationUpsertServiceV2Result! - upsertShopItem( - description: String! - endsAt: DateTime - groupUid: String! - id: ID - lydiaAccounId: String - max: Int! - name: String! - paymentMethods: [PaymentMethod!]! - price: Float! - startsAt: DateTime - stock: Int! - visibility: Visibility! - ): MutationUpsertShopItemResult! - upsertShopOptions(itemOptions: [ShopItemOptionInput!]!, shopItemId: String!): Boolean! - upsertShopPayment( - answers: [String!]! - id: ID - paymentMethod: String - phone: String - quantity: Int! - shopItemId: String! - userUid: String! - ): MutationUpsertShopPaymentResult! """ Créer ou modifier un thème """ @@ -3408,12 +3358,6 @@ type MutationDeleteServiceSuccess { data: Service! } -union MutationDeleteShopItemResult = Error | MutationDeleteShopItemSuccess | ZodError - -type MutationDeleteShopItemSuccess { - data: Boolean! -} - union MutationDeleteTicketGroupResult = Error | MutationDeleteTicketGroupSuccess | ZodError type MutationDeleteTicketGroupSuccess { @@ -3472,12 +3416,6 @@ type MutationOpposeRegistrationSuccess { data: Boolean! } -union MutationPaidShopPaymentResult = Error | MutationPaidShopPaymentSuccess | ZodError - -type MutationPaidShopPaymentSuccess { - data: ShopPayment! -} - union MutationPayBookingResult = Error | MutationPayBookingSuccess | ZodError type MutationPayBookingSuccess { @@ -3874,18 +3812,6 @@ type MutationUpsertServiceV2Success { data: Service! } -union MutationUpsertShopItemResult = Error | MutationUpsertShopItemSuccess | ZodError - -type MutationUpsertShopItemSuccess { - data: ShopItem! -} - -union MutationUpsertShopPaymentResult = Error | MutationUpsertShopPaymentSuccess | ZodError - -type MutationUpsertShopPaymentSuccess { - data: ShopPayment! -} - union MutationUpsertThemeResult = Error | MutationUpsertThemeSuccess | ZodError type MutationUpsertThemeSuccess { @@ -4093,12 +4019,6 @@ Numéro de téléphone, au format international (E.164, avec préfixes “+”), """ scalar PhoneNumber -type Picture { - id: ID! - path: String! - position: Int! -} - """ Une ressource qui possède une image associée """ @@ -4463,8 +4383,6 @@ type Query @rateLimit(limit: 1200, duration: 60) { """ mine: Boolean! ): [Service!]! - shopItem(slug: String!): ShopItem! - shopPayments(item: ID!): [ShopPayment!]! """ Identifiants des différentes promotions existantes """ @@ -5619,74 +5537,6 @@ interface Shareable { shares: Int! } -type ShopItem implements Node { - createdAt: DateTime! - description: String! - descriptionHtml: String! - endsAt: DateTime - group: Group! - id: ID! - itemOptions: [ShopItemOption!]! - """ - L'identifiant local de la ressource (sans préfixe) - """ - localID: LocalID! - lydiaAccount: LydiaAccount - max: Int! - name: String! - paymentMethods: [PaymentMethod!]! - pictures: [Picture!]! - price: Float! - shopPayments: [ShopPayment!]! - """ - Un nom lisible sans espaces, adaptés pour des URLs. - """ - slug: String! - startsAt: DateTime - stock: Int! - stockLeft: Int! - uid: String! @deprecated(reason: "Use `slug` instead. This field was never universally unique.") - updatedAt: DateTime! - visibility: Visibility! -} - -type ShopItemAnswer { - id: ID! - options: [String!]! - shopPayment: ShopPayment! - shopPaymentId: String! -} - -type ShopItemOption { - id: ID! - name: String! - options: [String!]! - otherToggle: Boolean! - required: Boolean! - shopItem: ShopItem! -} - -input ShopItemOptionInput { - id: String! - name: String! - options: [String!]! - otherToggle: Boolean! - required: Boolean! -} - -type ShopPayment { - createdAt: DateTime! - id: ID! - paid: Boolean! - paymentMethod: PaymentMethod! - quantity: Int! - shopItem: ShopItem! - shopItemAnswer: ShopItemAnswer - totalPrice: Float! - updatedAt: DateTime! - user: User! -} - """ Du texte de 200 caractères maximum """ diff --git a/packages/app/src/lib/typenames.ts b/packages/app/src/lib/typenames.ts index df47d0609..cbc0c3b14 100644 --- a/packages/app/src/lib/typenames.ts +++ b/packages/app/src/lib/typenames.ts @@ -37,11 +37,6 @@ export const ID_PREFIXES_TO_TYPENAMES = { reac: 'Reaction', promocode: 'PromotionCode', promo: 'Promotion', - picfile: 'Picture', - shopitem: 'ShopItem', - shoppayment: 'ShopPayment', - shopitemoption: 'ShopItemOption', - shopitemanswer: 'ShopItemAnswer', form: 'Form', formsection: 'FormSection', formjump: 'FormJump', diff --git a/packages/db/prisma/migrations/20241017131441_drop_shop/migration.sql b/packages/db/prisma/migrations/20241017131441_drop_shop/migration.sql new file mode 100644 index 000000000..112577960 --- /dev/null +++ b/packages/db/prisma/migrations/20241017131441_drop_shop/migration.sql @@ -0,0 +1,192 @@ +/* + Warnings: + + - You are about to drop the `Picture` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `ShopItem` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `ShopItemAnswer` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `ShopItemOption` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `ShopPayment` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `_PictureToShopItem` table. If the table is not empty, all the data it contains will be lost. + +*/ +-- DropForeignKey +ALTER TABLE "LydiaTransaction" DROP CONSTRAINT "LydiaTransaction_shopPaymentId_fkey"; + +-- DropForeignKey +ALTER TABLE "ShopItem" DROP CONSTRAINT "ShopItem_groupId_fkey"; + +-- DropForeignKey +ALTER TABLE "ShopItem" DROP CONSTRAINT "ShopItem_lydiaAccountId_fkey"; + +-- DropForeignKey +ALTER TABLE "ShopItemAnswer" DROP CONSTRAINT "ShopItemAnswer_shopPaymentId_fkey"; + +-- DropForeignKey +ALTER TABLE "ShopItemOption" DROP CONSTRAINT "ShopItemOption_shopItemId_fkey"; + +-- DropForeignKey +ALTER TABLE "ShopPayment" DROP CONSTRAINT "ShopPayment_shopItemId_fkey"; + +-- DropForeignKey +ALTER TABLE "ShopPayment" DROP CONSTRAINT "ShopPayment_userId_fkey"; + +-- DropForeignKey +ALTER TABLE "_PictureToShopItem" DROP CONSTRAINT "_PictureToShopItem_A_fkey"; + +-- DropForeignKey +ALTER TABLE "_PictureToShopItem" DROP CONSTRAINT "_PictureToShopItem_B_fkey"; + +-- AlterTable +ALTER TABLE "Announcement" ALTER COLUMN "id" SET DEFAULT nanoid('ann:'); + +-- AlterTable +ALTER TABLE "Answer" ALTER COLUMN "id" SET DEFAULT nanoid('answer:'); + +-- AlterTable +ALTER TABLE "Article" ALTER COLUMN "id" SET DEFAULT nanoid('a:'); + +-- AlterTable +ALTER TABLE "Bookmark" ALTER COLUMN "id" SET DEFAULT nanoid('bookmark:'); + +-- AlterTable +ALTER TABLE "Comment" ALTER COLUMN "id" SET DEFAULT nanoid('comment:'); + +-- AlterTable +ALTER TABLE "Contribution" ALTER COLUMN "id" SET DEFAULT nanoid('contribution:'); + +-- AlterTable +ALTER TABLE "ContributionOption" ALTER COLUMN "id" SET DEFAULT nanoid('contributionoption:'); + +-- AlterTable +ALTER TABLE "Credential" ALTER COLUMN "id" SET DEFAULT nanoid('credential:'); + +-- AlterTable +ALTER TABLE "Document" ALTER COLUMN "id" SET DEFAULT nanoid('doc:'); + +-- AlterTable +ALTER TABLE "EmailChange" ALTER COLUMN "id" SET DEFAULT nanoid('emailchange:'), +ALTER COLUMN "token" SET DEFAULT nanoid('', 30); + +-- AlterTable +ALTER TABLE "Event" ALTER COLUMN "id" SET DEFAULT nanoid('e:'); + +-- AlterTable +ALTER TABLE "EventManager" ALTER COLUMN "id" SET DEFAULT nanoid('em:'); + +-- AlterTable +ALTER TABLE "Form" ALTER COLUMN "id" SET DEFAULT nanoid('form:'); + +-- AlterTable +ALTER TABLE "FormJump" ALTER COLUMN "id" SET DEFAULT nanoid('formjump:'); + +-- AlterTable +ALTER TABLE "FormSection" ALTER COLUMN "id" SET DEFAULT nanoid('formsection:'); + +-- AlterTable +ALTER TABLE "GodparentRequest" ALTER COLUMN "id" SET DEFAULT nanoid('godparentreq:'); + +-- AlterTable +ALTER TABLE "Group" ALTER COLUMN "id" SET DEFAULT nanoid('g:'); + +-- AlterTable +ALTER TABLE "Link" ALTER COLUMN "id" SET DEFAULT nanoid('link:'); + +-- AlterTable +ALTER TABLE "LogEntry" ALTER COLUMN "id" SET DEFAULT nanoid('log:'); + +-- AlterTable +ALTER TABLE "LydiaAccount" ALTER COLUMN "id" SET DEFAULT nanoid('lydia:'); + +-- AlterTable +ALTER TABLE "LydiaTransaction" ALTER COLUMN "id" SET DEFAULT nanoid('lydiapayment:'); + +-- AlterTable +ALTER TABLE "Major" ALTER COLUMN "id" SET DEFAULT nanoid('major:'); + +-- AlterTable +ALTER TABLE "Minor" ALTER COLUMN "id" SET DEFAULT nanoid('minor:'); + +-- AlterTable +ALTER TABLE "Notification" ALTER COLUMN "id" SET DEFAULT nanoid('notif:'); + +-- AlterTable +ALTER TABLE "NotificationSubscription" ALTER COLUMN "id" SET DEFAULT nanoid('notifsub:'); + +-- AlterTable +ALTER TABLE "Page" ALTER COLUMN "id" SET DEFAULT nanoid('page:'); + +-- AlterTable +ALTER TABLE "PasswordReset" ALTER COLUMN "id" SET DEFAULT nanoid('passreset:'); + +-- AlterTable +ALTER TABLE "PaypalTransaction" ALTER COLUMN "id" SET DEFAULT nanoid('paypalpayment:'); + +-- AlterTable +ALTER TABLE "Promotion" ALTER COLUMN "id" SET DEFAULT nanoid('promo:'); + +-- AlterTable +ALTER TABLE "PromotionCode" ALTER COLUMN "id" SET DEFAULT nanoid('promocode:'); + +-- AlterTable +ALTER TABLE "Question" ALTER COLUMN "id" SET DEFAULT nanoid('question:'); + +-- AlterTable +ALTER TABLE "QuickSignup" ALTER COLUMN "id" SET DEFAULT nanoid('quicksignup:', 6); + +-- AlterTable +ALTER TABLE "Reaction" ALTER COLUMN "id" SET DEFAULT nanoid('reac:'); + +-- AlterTable +ALTER TABLE "Registration" ALTER COLUMN "id" SET DEFAULT nanoid('r:'); + +-- AlterTable +ALTER TABLE "School" ALTER COLUMN "id" SET DEFAULT nanoid('school:'), +ALTER COLUMN "aliasMailDomains" SET DEFAULT ARRAY[]::VARCHAR(255)[]; + +-- AlterTable +ALTER TABLE "Service" ALTER COLUMN "id" SET DEFAULT nanoid('service:'); + +-- AlterTable +ALTER TABLE "StudentAssociation" ALTER COLUMN "id" SET DEFAULT nanoid('ae:'); + +-- AlterTable +ALTER TABLE "Subject" ALTER COLUMN "id" SET DEFAULT nanoid('subj:'); + +-- AlterTable +ALTER TABLE "TeachingUnit" ALTER COLUMN "id" SET DEFAULT nanoid('ue:'); + +-- AlterTable +ALTER TABLE "Theme" ALTER COLUMN "id" SET DEFAULT nanoid('theme:'); + +-- AlterTable +ALTER TABLE "ThemeValue" ALTER COLUMN "id" SET DEFAULT nanoid('themeval:'); + +-- AlterTable +ALTER TABLE "Ticket" ALTER COLUMN "id" SET DEFAULT nanoid('t:'); + +-- AlterTable +ALTER TABLE "TicketGroup" ALTER COLUMN "id" SET DEFAULT nanoid('tg:'); + +-- AlterTable +ALTER TABLE "User" ALTER COLUMN "id" SET DEFAULT nanoid('u:'); + +-- AlterTable +ALTER TABLE "UserCandidate" ALTER COLUMN "id" SET DEFAULT nanoid('candidate:'); + +-- DropTable +DROP TABLE "Picture"; + +-- DropTable +DROP TABLE "ShopItem"; + +-- DropTable +DROP TABLE "ShopItemAnswer"; + +-- DropTable +DROP TABLE "ShopItemOption"; + +-- DropTable +DROP TABLE "ShopPayment"; + +-- DropTable +DROP TABLE "_PictureToShopItem"; diff --git a/packages/db/prisma/schema.prisma b/packages/db/prisma/schema.prisma index ee5df84d6..f91031491 100644 --- a/packages/db/prisma/schema.prisma +++ b/packages/db/prisma/schema.prisma @@ -88,7 +88,6 @@ model User { comments Comment[] bannedFromEvents Event[] @relation("bannedFromEvents") reactions Reaction[] - shopPayments ShopPayment[] formAnswers Answer[] createdForms Form[] completedForms Form[] @relation("completedForms") @@ -456,7 +455,6 @@ model Group { lyiaAccounts LydiaAccount[] tickets Ticket[] @relation("openTo") services Service[] - shopItems ShopItem[] restrictedFormSections FormSection[] @relation("restrictedTo") notifications Notification[] @@ -734,7 +732,6 @@ model LydiaAccount { events Event[] studentAssociation StudentAssociation? @relation(fields: [studentAssociationId], references: [id]) ContributionOption ContributionOption[] - shopItems ShopItem[] @@unique([privateToken, vendorToken, groupId]) } @@ -746,7 +743,6 @@ model LydiaTransaction { registrationId String? @unique registration Registration? @relation(fields: [registrationId], references: [id], onUpdate: Cascade, onDelete: Cascade) shopPaymentId String? @unique - shopPayment ShopPayment? @relation(fields: [shopPaymentId], references: [id], onUpdate: Cascade, onDelete: Cascade) requestId String? requestUuid String? transactionId String? @@ -991,76 +987,6 @@ model Promotion { events Event[] } -model Picture { - id String @id @default(dbgenerated("nanoid('picfile:')")) - path String @db.VarChar(255) - position Int @default(0) - ShopItems ShopItem[] -} - -model ShopItem { - id String @id @default(dbgenerated("nanoid('shopitem:')")) - slug String - name String @db.VarChar(255) - price Float @default(0) - stock Int @default(0) - max Int @default(0) - visibility Visibility @default(Private) - archived Boolean @default(false) - description String @default("") @db.Text - startsAt DateTime? - endsAt DateTime? - lydiaAccountId String? - groupId String - group Group @relation(fields: [groupId], references: [id], onDelete: Cascade, onUpdate: Cascade) - allowedPaymentMethods PaymentMethod[] @default([]) - pictures Picture[] - shopPayments ShopPayment[] - lydiaAccount LydiaAccount? @relation(fields: [lydiaAccountId], references: [id], onDelete: SetNull, onUpdate: Cascade) - itemOptions ShopItemOption[] - - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - - @@unique([groupId, slug]) -} - -model ShopPayment { - id String @id @default(dbgenerated("nanoid('shoppayment:')")) - shopItemId String - userId String - paid Boolean @default(false) - quantity Int @default(1) - totalPrice Float - paymentMethod PaymentMethod - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - - shopItem ShopItem @relation(fields: [shopItemId], references: [id], onDelete: Cascade, onUpdate: Cascade) - user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade) - lydiaTransaction LydiaTransaction? - shopItemAnswer ShopItemAnswer? -} - -model ShopItemOption { - id String @id @default(dbgenerated("nanoid('shopitemoption:')")) - name String @db.VarChar(255) - shopItemId String - options String[] @default([]) - shopItem ShopItem @relation(fields: [shopItemId], references: [id], onDelete: Cascade, onUpdate: Cascade) - required Boolean @default(false) - otherToggle Boolean @default(false) -} - -model ShopItemAnswer { - id String @id @default(dbgenerated("nanoid('shopitemanswer:')")) - shopPaymentId String - option String[] @default([]) - shopPayment ShopPayment @relation(fields: [shopPaymentId], references: [id], onDelete: Cascade, onUpdate: Cascade) - - @@unique([shopPaymentId]) -} - model Form { id String @id @default(dbgenerated("nanoid('form:')")) createdAt DateTime @default(now()) diff --git a/packages/db/seed/index.ts b/packages/db/seed/index.ts index e25b67206..38f7badc3 100644 --- a/packages/db/seed/index.ts +++ b/packages/db/seed/index.ts @@ -1171,50 +1171,6 @@ await prisma.ticket.update({ }, }); -const thirdPartyAppClub = await prisma.group.findUniqueOrThrow({ - where: { uid: faker.helpers.arrayElement(groups).uid }, -}); - -await prisma.shopItem.create({ - data: { - slug: 'boules-quies', - name: 'Boules quies', - description: 'Acheter des boules quies pour pas entendre Téo', - price: 10, - stock: 0, - max: 5, - visibility: Visibility.Public, - group: { connect: { uid: 'ski' } }, - }, -}); - -await prisma.shopItem.create({ - data: { - slug: 'server', - name: 'Server', - description: 'Atom 2 duo', - price: 100_000, - stock: 1, - max: 5, - visibility: Visibility.GroupRestricted, - group: { connect: { uid: 'ski' } }, - }, -}); - -await prisma.shopItem.create({ - data: { - slug: 'rechauffement', - name: 'Réchauffement Climatique', - description: - "Acheter un peu de réchauffement climatique, c'est gratuit et on en a en trop ! ![](https://jancovici.com/wp-content/uploads/2016/10/GES_graph13_en.png)", - price: 0, - stock: 0, - max: 0, - visibility: Visibility.Public, - group: { connect: { uid: 'bdd-ae-eau-2022' } }, - }, -}); - for (let i = 0; i < 10; i++) { const opensAt = i === 0 ? faker.date.soon() : faker.date.anytime(); const form = await prisma.form.create({ From 8b0085afa9502c5d7a60c9bcf7666e6cf7949451 Mon Sep 17 00:00:00 2001 From: Ewen Le Bihan Date: Thu, 17 Oct 2024 16:52:56 +0200 Subject: [PATCH 2/2] build(shop): remove shop-specific components --- .../src/lib/components/FormPictureItem.svelte | 125 ------ .../src/lib/components/FormShopItem.svelte | 380 ------------------ .../src/lib/components/ItemBuyingTable.svelte | 164 -------- .../app/src/lib/components/ItemOrder.svelte | 137 ------- 4 files changed, 806 deletions(-) delete mode 100644 packages/app/src/lib/components/FormPictureItem.svelte delete mode 100644 packages/app/src/lib/components/FormShopItem.svelte delete mode 100644 packages/app/src/lib/components/ItemBuyingTable.svelte delete mode 100644 packages/app/src/lib/components/ItemOrder.svelte diff --git a/packages/app/src/lib/components/FormPictureItem.svelte b/packages/app/src/lib/components/FormPictureItem.svelte deleted file mode 100644 index 0896b9d29..000000000 --- a/packages/app/src/lib/components/FormPictureItem.svelte +++ /dev/null @@ -1,125 +0,0 @@ - - -
- -
-
- {#key index} - p.path)} /> - {/key} -
-
- - { - inputElement.click(); - }} - icon={IconAdd}>Ajouter - Supprimer -
-
-
-
- - diff --git a/packages/app/src/lib/components/FormShopItem.svelte b/packages/app/src/lib/components/FormShopItem.svelte deleted file mode 100644 index 138766164..000000000 --- a/packages/app/src/lib/components/FormShopItem.svelte +++ /dev/null @@ -1,380 +0,0 @@ - - -
-
- -
-
-
- {#if !deleting} - {#if data.id !== ''} - { - deleting = true; - }}>Supprimer - {/if} - Enregistrer - {#if serverError} - {serverError} - {/if} - {:else} -

Es-tu sûr·e ?

- { - deleting = false; - }}>Annuler - { - deleting = false; - const { deleteShopItem } = await $zeus.mutate({ - deleteShopItem: [ - { itemId: data.id, groupUid: data.group.uid }, - { - '__typename': true, - '...on Error': { message: true }, - '...on ZodError': { message: true }, - '...on MutationDeleteShopItemSuccess': { data: true }, - }, - ], - }); - if (deleteShopItem.__typename === 'Error') { - toasts.error('Impossible de supprimer', deleteShopItem.message); - } else { - toasts.success('Article supprimé', `L'article ${data.name} a bien été supprimé`, { - lifetime: 2500, - showLifetime: true, - }); - await goto(`/groups/${data.group.uid}/shop/`); - } - }} - danger>Oui - {/if} -
-
- - diff --git a/packages/app/src/lib/components/ItemBuyingTable.svelte b/packages/app/src/lib/components/ItemBuyingTable.svelte deleted file mode 100644 index c17af727d..000000000 --- a/packages/app/src/lib/components/ItemBuyingTable.svelte +++ /dev/null @@ -1,164 +0,0 @@ - - -
- - - - - - - {#each options as option} - - {/each} - - - - - - {#each payments as payment} - - - - - {#each options.keys() as i} - - {/each} - - - - - {/each} - -
UserQuantitéPrix total{option.name}Payé ?Via
- - x{payment.quantity}{payment.totalPrice} €{payment.shopItemAnswer?.options[i] ?? '(sans réponse)'}{payment.paid ? 'Oui' : 'Non'} - - - updatePaidStatus(payment.id)} - > - {#if payment.paid} - - {:else} - - {/if} - -
-
- - diff --git a/packages/app/src/lib/components/ItemOrder.svelte b/packages/app/src/lib/components/ItemOrder.svelte deleted file mode 100644 index c5c47e83a..000000000 --- a/packages/app/src/lib/components/ItemOrder.svelte +++ /dev/null @@ -1,137 +0,0 @@ - - -
- p.path)} /> -
-

{order.shopItem.name}

-
-

{order.totalPrice} €

- -

-
-
- {#if !paying && !order.paid && order.paymentMethod === 'Lydia'} - - {/if} - {#if paying} -
{ - paymentLoading = true; - const { paidShopPayment } = await $zeus.mutate({ - paidShopPayment: [ - { - shopPaymentId: order.id, - phone, - paymentMethod: PaymentMethod.Lydia, - }, - { - '__typename': true, - '...on Error': { message: true }, - '...on ZodError': { message: true }, - '...on MutationPaidShopPaymentSuccess': { - data: { - __typename: true, - }, - }, - }, - ], - }); - if (paidShopPayment.__typename === 'MutationPaidShopPaymentSuccess') { - await goto('?' + new URLSearchParams({ done: order.id }).toString()); - paymentLoading = false; - toasts.add('success', 'La demande de paiement a été envoyée'); - } else { - const serverError = paidShopPayment.message; - paymentLoading = false; - toasts.add('error', serverError); - return; - } - }} - > - - -
- Payer {order.totalPrice}€ -
- - {/if} -
- -