From 426f94b6522bf072e7abab6496f39d82f1d65f1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Loipf=C3=BChrer?= Date: Fri, 6 Sep 2024 21:22:55 +0200 Subject: [PATCH 1/9] feat(web): rework group settings into one single page --- .../AuthenticatedLayout.tsx | 26 +------- frontend/apps/web/src/pages/groups/Group.tsx | 8 +-- frontend/apps/web/src/pages/groups/index.ts | 1 + .../groups/{ => settings}/GroupInvites.tsx | 46 +++++--------- .../groups/{ => settings}/GroupMemberList.tsx | 23 +++---- .../groups/settings/GroupSettingsPage.tsx | 61 +++++++++++++++++++ .../SettingsForm.tsx} | 54 ++++++---------- .../web/src/pages/groups/settings/index.ts | 1 + frontend/libs/translations/src/lib/de.ts | 6 +- frontend/libs/translations/src/lib/en.ts | 7 +-- frontend/libs/utils/src/index.ts | 1 + frontend/libs/utils/src/lib/useQueryVar.ts | 15 +++++ frontend/tsconfig.base.json | 4 +- 13 files changed, 134 insertions(+), 119 deletions(-) create mode 100644 frontend/apps/web/src/pages/groups/index.ts rename frontend/apps/web/src/pages/groups/{ => settings}/GroupInvites.tsx (86%) rename frontend/apps/web/src/pages/groups/{ => settings}/GroupMemberList.tsx (94%) create mode 100644 frontend/apps/web/src/pages/groups/settings/GroupSettingsPage.tsx rename frontend/apps/web/src/pages/groups/{GroupSettings.tsx => settings/SettingsForm.tsx} (86%) create mode 100644 frontend/apps/web/src/pages/groups/settings/index.ts create mode 100644 frontend/libs/utils/src/lib/useQueryVar.ts diff --git a/frontend/apps/web/src/app/authenticated-layout/AuthenticatedLayout.tsx b/frontend/apps/web/src/app/authenticated-layout/AuthenticatedLayout.tsx index 40b0717..807c0d2 100644 --- a/frontend/apps/web/src/app/authenticated-layout/AuthenticatedLayout.tsx +++ b/frontend/apps/web/src/app/authenticated-layout/AuthenticatedLayout.tsx @@ -28,16 +28,14 @@ import { AccountBalance, Event as EventIcon, AccountCircle as AccountCircleIcon, - AdminPanelSettings, BarChart, BugReport, GitHub, Logout, - Mail, Menu as MenuIcon, Message, Paid, - People, + Settings as SettingsIcon, } from "@mui/icons-material"; import { useTheme } from "@mui/material/styles"; import { Banner } from "@/components/style/Banner"; @@ -129,28 +127,10 @@ export const AuthenticatedLayout: React.FC = () => { selected={location.pathname.startsWith(`/groups/${groupId}/detail`)} > - + - - - - - - - - - - - - { - + diff --git a/frontend/apps/web/src/pages/groups/Group.tsx b/frontend/apps/web/src/pages/groups/Group.tsx index bab83cb..df26405 100644 --- a/frontend/apps/web/src/pages/groups/Group.tsx +++ b/frontend/apps/web/src/pages/groups/Group.tsx @@ -19,10 +19,8 @@ import { PersonalAccountList } from "../accounts/PersonalAccountList"; import { ClearingAccountList } from "../accounts/ClearingAccountList"; import { TransactionList } from "../transactions/TransactionList"; import { SettlementPlanDisplay } from "../accounts/SettlementPlanDisplay"; -import { GroupInvites } from "./GroupInvites"; import { GroupLog } from "./GroupLog"; -import { GroupMemberList } from "./GroupMemberList"; -import { GroupSettings } from "./GroupSettings"; +import { GroupSettingsPage } from "./settings"; import { TransactionDetail } from "../transactions/TransactionDetail"; import { SerializedError } from "@reduxjs/toolkit"; @@ -84,9 +82,7 @@ export const Group: React.FC = () => { } /> } /> } /> - } /> - } /> - } /> + } /> } /> } /> } /> diff --git a/frontend/apps/web/src/pages/groups/index.ts b/frontend/apps/web/src/pages/groups/index.ts new file mode 100644 index 0000000..dcf101b --- /dev/null +++ b/frontend/apps/web/src/pages/groups/index.ts @@ -0,0 +1 @@ +export * from "./settings"; diff --git a/frontend/apps/web/src/pages/groups/GroupInvites.tsx b/frontend/apps/web/src/pages/groups/settings/GroupInvites.tsx similarity index 86% rename from frontend/apps/web/src/pages/groups/GroupInvites.tsx rename to frontend/apps/web/src/pages/groups/settings/GroupInvites.tsx index b39dfe0..4e6d322 100644 --- a/frontend/apps/web/src/pages/groups/GroupInvites.tsx +++ b/frontend/apps/web/src/pages/groups/settings/GroupInvites.tsx @@ -8,59 +8,48 @@ import { subscribe, unsubscribe, useCurrentUserPermissions, - useGroup, } from "@abrechnung/redux"; import { Add, ContentCopy, Delete } from "@mui/icons-material"; -import { - Alert, - Grid, - IconButton, - List, - ListItem, - ListItemSecondaryAction, - ListItemText, - Typography, -} from "@mui/material"; +import { Alert, Grid, IconButton, List, ListItem, ListItemSecondaryAction, ListItemText } from "@mui/material"; import { DateTime } from "luxon"; import React, { useEffect, useState } from "react"; import { toast } from "react-toastify"; import { InviteLinkCreate } from "@/components/groups/InviteLinkCreate"; import { Loading } from "@/components/style/Loading"; -import { MobilePaper } from "@/components/style"; import { api, ws } from "@/core/api"; import { useTitle } from "@/core/utils"; import { useAppDispatch, useAppSelector } from "@/store"; import { useTranslation } from "react-i18next"; import { Navigate } from "react-router-dom"; +import { Group } from "@abrechnung/api"; -interface Props { - groupId: number; +interface GroupInviteProps { + group: Group; } -export const GroupInvites: React.FC = ({ groupId }) => { +export const GroupInvites: React.FC = ({ group }) => { const { t } = useTranslation(); const [showModal, setShowModal] = useState(false); const dispatch = useAppDispatch(); - const group = useGroup(groupId); - const invites = useAppSelector((state) => selectGroupInvites(state, groupId)); - const members = useAppSelector((state) => selectGroupMembers(state, groupId)); - const permissions = useCurrentUserPermissions(groupId); - const invitesLoadingStatus = useAppSelector((state) => selectGroupInviteStatus(state, groupId)); + const invites = useAppSelector((state) => selectGroupInvites(state, group.id)); + const members = useAppSelector((state) => selectGroupMembers(state, group.id)); + const permissions = useCurrentUserPermissions(group.id); + const invitesLoadingStatus = useAppSelector((state) => selectGroupInviteStatus(state, group.id)); const isGuest = useAppSelector(selectIsGuestUser); useTitle(t("groups.invites.tabTitle", "", { groupName: group?.name })); useEffect(() => { - dispatch(fetchGroupInvites({ groupId, api })); - dispatch(subscribe({ subscription: { type: "group_invite", groupId }, websocket: ws })); + dispatch(fetchGroupInvites({ groupId: group.id, api })); + dispatch(subscribe({ subscription: { type: "group_invite", groupId: group.id }, websocket: ws })); return () => { - dispatch(unsubscribe({ subscription: { type: "group_invite", groupId }, websocket: ws })); + dispatch(unsubscribe({ subscription: { type: "group_invite", groupId: group.id }, websocket: ws })); }; - }, [dispatch, groupId]); + }, [dispatch, group]); const deleteToken = (id: number) => { - dispatch(deleteGroupInvite({ groupId, inviteId: id, api })) + dispatch(deleteGroupInvite({ groupId: group.id, inviteId: id, api })) .unwrap() .catch((err) => { toast.error(err); @@ -94,10 +83,7 @@ export const GroupInvites: React.FC = ({ groupId }) => { } return ( - - - {t("groups.invites.header")} - + <> {isGuest && {t("groups.invites.guestUserDisclaimer")}} {invitesLoadingStatus === "loading" ? ( @@ -163,6 +149,6 @@ export const GroupInvites: React.FC = ({ groupId }) => { setShowModal(false)} group={group} /> )} - + ); }; diff --git a/frontend/apps/web/src/pages/groups/GroupMemberList.tsx b/frontend/apps/web/src/pages/groups/settings/GroupMemberList.tsx similarity index 94% rename from frontend/apps/web/src/pages/groups/GroupMemberList.tsx rename to frontend/apps/web/src/pages/groups/settings/GroupMemberList.tsx index 8c69fe9..bcb5bae 100644 --- a/frontend/apps/web/src/pages/groups/GroupMemberList.tsx +++ b/frontend/apps/web/src/pages/groups/settings/GroupMemberList.tsx @@ -1,10 +1,9 @@ -import { GroupMember } from "@abrechnung/api"; +import { Group, GroupMember } from "@abrechnung/api"; import { selectCurrentUserId, selectGroupMembers, updateGroupMemberPrivileges, useCurrentUserPermissions, - useGroup, } from "@abrechnung/redux"; import { Edit } from "@mui/icons-material"; import { @@ -27,15 +26,14 @@ import { Form, Formik, FormikHelpers } from "formik"; import { DateTime } from "luxon"; import React, { useState } from "react"; import { toast } from "react-toastify"; -import { MobilePaper } from "@/components/style"; import { api } from "@/core/api"; import { useTitle } from "@/core/utils"; import { useAppDispatch, useAppSelector } from "@/store"; import { useTranslation } from "react-i18next"; import { Navigate } from "react-router-dom"; -interface Props { - groupId: number; +interface GroupMemberListProps { + group: Group; } type FormValues = { @@ -44,13 +42,12 @@ type FormValues = { canWrite: boolean; }; -export const GroupMemberList: React.FC = ({ groupId }) => { +export const GroupMemberList: React.FC = ({ group }) => { const { t } = useTranslation(); const dispatch = useAppDispatch(); const currentUserId = useAppSelector(selectCurrentUserId); - const members = useAppSelector((state) => selectGroupMembers(state, groupId)); - const group = useGroup(groupId); - const permissions = useCurrentUserPermissions(groupId); + const members = useAppSelector((state) => selectGroupMembers(state, group.id)); + const permissions = useCurrentUserPermissions(group.id); const [memberToEdit, setMemberToEdit] = useState(undefined); @@ -59,7 +56,7 @@ export const GroupMemberList: React.FC = ({ groupId }) => { const handleEditMemberSubmit = (values: FormValues, { setSubmitting }: FormikHelpers) => { dispatch( updateGroupMemberPrivileges({ - groupId, + groupId: group.id, memberId: values.userId, permissions: { canWrite: values.canWrite, isOwner: values.isOwner }, api, @@ -100,7 +97,7 @@ export const GroupMemberList: React.FC = ({ groupId }) => { } return ( - + <> {members.length === 0 ? ( @@ -164,7 +161,7 @@ export const GroupMemberList: React.FC = ({ groupId }) => { /> {(permissions.is_owner || permissions.can_write) && ( - openEditMemberModal(member.user_id)}> + openEditMemberModal(member.user_id)}> @@ -224,6 +221,6 @@ export const GroupMemberList: React.FC = ({ groupId }) => { - + ); }; diff --git a/frontend/apps/web/src/pages/groups/settings/GroupSettingsPage.tsx b/frontend/apps/web/src/pages/groups/settings/GroupSettingsPage.tsx new file mode 100644 index 0000000..3e01e6a --- /dev/null +++ b/frontend/apps/web/src/pages/groups/settings/GroupSettingsPage.tsx @@ -0,0 +1,61 @@ +import { MobilePaper } from "@/components/style"; +import { useTitle } from "@/core/utils"; +import { useCurrentUserPermissions, useGroup } from "@abrechnung/redux"; +import { Alert, Box, Stack, Tab } from "@mui/material"; +import * as React from "react"; +import { useTranslation } from "react-i18next"; +import { Navigate } from "react-router-dom"; +import { SettingsForm } from "./SettingsForm"; +import { GroupMemberList } from "./GroupMemberList"; +import { TabContext, TabList, TabPanel } from "@mui/lab"; +import { useQueryVar } from "@abrechnung/utils"; +import { GroupInvites } from "./GroupInvites"; + +interface Props { + groupId: number; +} + +export const GroupSettingsPage: React.FC = ({ groupId }) => { + const { t } = useTranslation(); + const [activeTab, setActiveTab] = useQueryVar("activeTab", "settings"); + + const group = useGroup(groupId); + const permissions = useCurrentUserPermissions(groupId); + + useTitle(t("groups.settings.tabTitle", "", { groupName: group?.name })); + + if (!permissions || !group) { + return ; + } + + return ( + + + setActiveTab(newVal)}> + + + + + + + + {permissions.is_owner ? ( + {t("groups.settings.ownerDisclaimer")} + ) : !permissions.can_write ? ( + {t("groups.settings.readAccessDisclaimer")} + ) : null} + + + + + + + + + + + + + + ); +}; diff --git a/frontend/apps/web/src/pages/groups/GroupSettings.tsx b/frontend/apps/web/src/pages/groups/settings/SettingsForm.tsx similarity index 86% rename from frontend/apps/web/src/pages/groups/GroupSettings.tsx rename to frontend/apps/web/src/pages/groups/settings/SettingsForm.tsx index ef867ac..70c1049 100644 --- a/frontend/apps/web/src/pages/groups/GroupSettings.tsx +++ b/frontend/apps/web/src/pages/groups/settings/SettingsForm.tsx @@ -1,4 +1,5 @@ -import { leaveGroup, updateGroup, useCurrentUserPermissions, useGroup } from "@abrechnung/redux"; +import * as React from "react"; +import { leaveGroup, updateGroup, useCurrentUserPermissions } from "@abrechnung/redux"; import { Cancel, Edit, Save } from "@mui/icons-material"; import { Alert, @@ -14,17 +15,19 @@ import { LinearProgress, } from "@mui/material"; import { Form, Formik, FormikHelpers } from "formik"; -import React, { useState } from "react"; -import { Navigate, useNavigate } from "react-router-dom"; +import { useNavigate } from "react-router-dom"; import { toast } from "react-toastify"; import { z } from "zod"; import { DisabledFormControlLabel, DisabledTextField } from "@/components/style/DisabledTextField"; -import { MobilePaper } from "@/components/style"; import { api } from "@/core/api"; -import { useTitle } from "@/core/utils"; import { useAppDispatch } from "@/store"; import { toFormikValidationSchema } from "@abrechnung/utils"; import { useTranslation } from "react-i18next"; +import { Group } from "@abrechnung/api"; + +type SettingsFormProps = { + group: Group; +}; const validationSchema = z.object({ name: z.string({ required_error: "group name is required" }), @@ -36,22 +39,15 @@ const validationSchema = z.object({ type FormValues = z.infer; -interface Props { - groupId: number; -} - -export const GroupSettings: React.FC = ({ groupId }) => { +export const SettingsForm: React.FC = ({ group }) => { const { t } = useTranslation(); - const [showLeaveModal, setShowLeaveModal] = useState(false); - const navigate = useNavigate(); + const [showLeaveModal, setShowLeaveModal] = React.useState(false); const dispatch = useAppDispatch(); + const navigate = useNavigate(); - const group = useGroup(groupId); - const permissions = useCurrentUserPermissions(groupId); - - const [isEditing, setIsEditing] = useState(false); + const permissions = useCurrentUserPermissions(group.id); - useTitle(t("groups.settings.tabTitle", "", { groupName: group?.name })); + const [isEditing, setIsEditing] = React.useState(false); const startEdit = () => { setIsEditing(true); @@ -90,7 +86,7 @@ export const GroupSettings: React.FC = ({ groupId }) => { }; const confirmLeaveGroup = () => { - dispatch(leaveGroup({ groupId, api })) + dispatch(leaveGroup({ groupId: group.id, api })) .unwrap() .then(() => { navigate("/"); @@ -101,17 +97,11 @@ export const GroupSettings: React.FC = ({ groupId }) => { }; if (!permissions || !group) { - return ; + return Error loading group permissions; } return ( - - {permissions.is_owner ? ( - {t("groups.settings.ownerDisclaimer")} - ) : !permissions.can_write ? ( - {t("groups.settings.readAccessDisclaimer")} - ) : null} - + <> = ({ groupId }) => { )} - - {/**/} - {/* */} - {/* */} - {/* */} - {/* */} - {/* */} - {/* */} - {/**/} - setShowLeaveModal(false)}> {t("groups.settings.leaveGroup")} @@ -264,6 +244,6 @@ export const GroupSettings: React.FC = ({ groupId }) => { - + ); }; diff --git a/frontend/apps/web/src/pages/groups/settings/index.ts b/frontend/apps/web/src/pages/groups/settings/index.ts new file mode 100644 index 0000000..60317de --- /dev/null +++ b/frontend/apps/web/src/pages/groups/settings/index.ts @@ -0,0 +1 @@ +export * from "./GroupSettingsPage"; diff --git a/frontend/libs/translations/src/lib/de.ts b/frontend/libs/translations/src/lib/de.ts index b488eb4..d4f3788 100644 --- a/frontend/libs/translations/src/lib/de.ts +++ b/frontend/libs/translations/src/lib/de.ts @@ -59,10 +59,8 @@ const translations = { events: "Ereignisse", balances: "Salden", accounts: "Konten", - groupSettings: "Gruppeneinstellungen", - groupMembers: "Gruppenmitglieder", - groupInvites: "Gruppeneinladungen", - groupLog: "Gruppenprotokoll", + groupSettings: "Einstellungen", + activity: "Aktivität", profile: "Profil", settings: "Einstellungen", sessions: "Sitzungen", diff --git a/frontend/libs/translations/src/lib/en.ts b/frontend/libs/translations/src/lib/en.ts index bdd36ba..1d8937d 100644 --- a/frontend/libs/translations/src/lib/en.ts +++ b/frontend/libs/translations/src/lib/en.ts @@ -54,10 +54,8 @@ const translations = { events: "Events", balances: "Balances", accounts: "Accounts", - groupSettings: "Group Settings", - groupMembers: "Group Members", - groupInvites: "Group Invites", - groupLog: "Group Log", + groupSettings: "Settings", + activity: "Activity", profile: "Profile", settings: "Settings", sessions: "Sessions", @@ -95,6 +93,7 @@ const translations = { }, settings: { tabTitle: "{{groupName}} - Settings", + header: "Settings", ownerDisclaimer: "You are an owner of this group", readAccessDisclaimer: "You only have read access to this group", terms: "Terms", diff --git a/frontend/libs/utils/src/index.ts b/frontend/libs/utils/src/index.ts index 1ce455a..e699c42 100644 --- a/frontend/libs/utils/src/index.ts +++ b/frontend/libs/utils/src/index.ts @@ -3,3 +3,4 @@ export * from "./lib/validators"; export * from "./lib/event-emitter"; export * from "./lib/floats"; export * from "./lib/csv"; +export * from "./lib/useQueryVar"; diff --git a/frontend/libs/utils/src/lib/useQueryVar.ts b/frontend/libs/utils/src/lib/useQueryVar.ts new file mode 100644 index 0000000..d41dca7 --- /dev/null +++ b/frontend/libs/utils/src/lib/useQueryVar.ts @@ -0,0 +1,15 @@ +import { useSearchParams } from "react-router-dom"; + +export const useQueryVar = ( + name: string, + defaultValue: Val +): [string | Val, (val: string) => void] => { + const [searchParams, setSearchParams] = useSearchParams(); + + const updateVal = (val: string) => { + searchParams.set(name, val); + setSearchParams(new URLSearchParams(searchParams)); + }; + + return [searchParams.get(name) ?? defaultValue, updateVal]; +}; diff --git a/frontend/tsconfig.base.json b/frontend/tsconfig.base.json index 54567a6..4a83e72 100644 --- a/frontend/tsconfig.base.json +++ b/frontend/tsconfig.base.json @@ -16,9 +16,9 @@ "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "importHelpers": true, - "target": "es2015", + "target": "es2019", "module": "esnext", - "lib": ["es2017", "dom"], + "lib": ["es2019", "dom"], "skipLibCheck": true, "skipDefaultLibCheck": true, "baseUrl": ".", From 913961045c764ea442189211708d690367136678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Loipf=C3=BChrer?= Date: Fri, 6 Sep 2024 22:11:51 +0200 Subject: [PATCH 2/9] refactor(frontend): reenable type checking for translations --- frontend/apps/mobile/src/@types/i18next.d.ts | 4 +--- frontend/apps/web/src/@types/i18next.d.ts | 4 +--- frontend/libs/translations/src/lib/en.ts | 1 + 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/frontend/apps/mobile/src/@types/i18next.d.ts b/frontend/apps/mobile/src/@types/i18next.d.ts index 81d1906..42371d0 100644 --- a/frontend/apps/mobile/src/@types/i18next.d.ts +++ b/frontend/apps/mobile/src/@types/i18next.d.ts @@ -4,9 +4,7 @@ import type { resources, defaultNS } from "@abrechnung/translations"; declare module "i18next" { interface CustomTypeOptions { defaultNS: typeof defaultNS; - nsSeparator: ""; - resources: { "": (typeof resources)["en"]["translations"] }; // the following should be working but has apparently been broken in i18next 23.x - // resources: (typeof resources)["en"]; + resources: (typeof resources)["en"]; } } diff --git a/frontend/apps/web/src/@types/i18next.d.ts b/frontend/apps/web/src/@types/i18next.d.ts index 81d1906..42371d0 100644 --- a/frontend/apps/web/src/@types/i18next.d.ts +++ b/frontend/apps/web/src/@types/i18next.d.ts @@ -4,9 +4,7 @@ import type { resources, defaultNS } from "@abrechnung/translations"; declare module "i18next" { interface CustomTypeOptions { defaultNS: typeof defaultNS; - nsSeparator: ""; - resources: { "": (typeof resources)["en"]["translations"] }; // the following should be working but has apparently been broken in i18next 23.x - // resources: (typeof resources)["en"]; + resources: (typeof resources)["en"]; } } diff --git a/frontend/libs/translations/src/lib/en.ts b/frontend/libs/translations/src/lib/en.ts index 1d8937d..ce29191 100644 --- a/frontend/libs/translations/src/lib/en.ts +++ b/frontend/libs/translations/src/lib/en.ts @@ -231,6 +231,7 @@ const translations = { }, auth: { register: { + title: "Register", tabTitle: "Abrechnung - Register", header: "Register a new account", confirmButton: "Register", From e12fe45924408a146725011f98e01d4b86a71084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Loipf=C3=BChrer?= Date: Fri, 6 Sep 2024 22:38:46 +0200 Subject: [PATCH 3/9] refactor(web): rename group log to group activity --- .../PersonalAccountListItem.tsx | 31 +++----- frontend/apps/web/src/pages/groups/Group.tsx | 4 +- .../{GroupLog.tsx => GroupActivity.tsx} | 72 ++----------------- .../pages/groups/settings/SettingsForm.tsx | 4 +- frontend/libs/translations/src/lib/de.ts | 6 +- frontend/libs/translations/src/lib/en.ts | 6 +- 6 files changed, 21 insertions(+), 102 deletions(-) rename frontend/apps/web/src/pages/groups/{GroupLog.tsx => GroupActivity.tsx} (54%) diff --git a/frontend/apps/web/src/pages/accounts/PersonalAccountList/PersonalAccountListItem.tsx b/frontend/apps/web/src/pages/accounts/PersonalAccountList/PersonalAccountListItem.tsx index b869249..2292813 100644 --- a/frontend/apps/web/src/pages/accounts/PersonalAccountList/PersonalAccountListItem.tsx +++ b/frontend/apps/web/src/pages/accounts/PersonalAccountList/PersonalAccountListItem.tsx @@ -1,12 +1,13 @@ -import { accountEditStarted, selectGroupMemberIdToUsername, useCurrentUserPermissions } from "@abrechnung/redux"; +import { accountEditStarted, useCurrentUserPermissions } from "@abrechnung/redux"; import { Delete, Edit } from "@mui/icons-material"; import { Chip, IconButton, ListItem, ListItemSecondaryAction, ListItemText } from "@mui/material"; import React from "react"; import { Navigate, useNavigate } from "react-router-dom"; import { ListItemLink } from "@/components/style/ListItemLink"; -import { useAppDispatch, useAppSelector } from "@/store"; +import { useAppDispatch } from "@/store"; import { getAccountLink } from "@/utils"; import { Account } from "@abrechnung/types"; +import { useTranslation } from "react-i18next"; interface Props { groupId: number; @@ -16,11 +17,11 @@ interface Props { } export const PersonalAccountListItem: React.FC = ({ groupId, currentUserId, account, setAccountToDelete }) => { + const { t } = useTranslation(); const dispatch = useAppDispatch(); const navigate = useNavigate(); const permissions = useCurrentUserPermissions(groupId); - const memberIDToUsername = useAppSelector((state) => selectGroupMemberIdToUsername(state, groupId)); if (!permissions || !account) { return ; @@ -33,26 +34,10 @@ export const PersonalAccountListItem: React.FC = ({ groupId, currentUserI navigate(getAccountLink(groupId, account.type, account.id)); }; let owningUserInfo = null; - if (account.type === "personal" && account.owning_user_id !== null) { - if (account.owning_user_id === currentUserId) { - owningUserInfo = ( - - , owned by - - ); - } else { - owningUserInfo = ( - - , owned by{" "} - - - ); - } + if (account.type === "personal" && account.owning_user_id === currentUserId) { + owningUserInfo = ( + + ); } return ( diff --git a/frontend/apps/web/src/pages/groups/Group.tsx b/frontend/apps/web/src/pages/groups/Group.tsx index df26405..90639e4 100644 --- a/frontend/apps/web/src/pages/groups/Group.tsx +++ b/frontend/apps/web/src/pages/groups/Group.tsx @@ -19,7 +19,7 @@ import { PersonalAccountList } from "../accounts/PersonalAccountList"; import { ClearingAccountList } from "../accounts/ClearingAccountList"; import { TransactionList } from "../transactions/TransactionList"; import { SettlementPlanDisplay } from "../accounts/SettlementPlanDisplay"; -import { GroupLog } from "./GroupLog"; +import { GroupActivity } from "./GroupActivity"; import { GroupSettingsPage } from "./settings"; import { TransactionDetail } from "../transactions/TransactionDetail"; import { SerializedError } from "@reduxjs/toolkit"; @@ -79,7 +79,7 @@ export const Group: React.FC = () => { return ( }> - } /> + } /> } /> } /> } /> diff --git a/frontend/apps/web/src/pages/groups/GroupLog.tsx b/frontend/apps/web/src/pages/groups/GroupActivity.tsx similarity index 54% rename from frontend/apps/web/src/pages/groups/GroupLog.tsx rename to frontend/apps/web/src/pages/groups/GroupActivity.tsx index 925ba55..d0a6d43 100644 --- a/frontend/apps/web/src/pages/groups/GroupLog.tsx +++ b/frontend/apps/web/src/pages/groups/GroupActivity.tsx @@ -7,20 +7,9 @@ import { unsubscribe, useGroup, } from "@abrechnung/redux"; -import { - Button, - Divider, - FormControlLabel, - List, - ListItem, - ListItemText, - Switch, - TextField, - Typography, -} from "@mui/material"; +import { List, ListItem, ListItemText, Typography } from "@mui/material"; import { DateTime } from "luxon"; -import React, { useEffect, useState } from "react"; -import { toast } from "react-toastify"; +import React, { useEffect } from "react"; import { Loading } from "@/components/style/Loading"; import { MobilePaper } from "@/components/style"; import { api, ws } from "@/core/api"; @@ -32,17 +21,14 @@ interface Props { groupId: number; } -export const GroupLog: React.FC = ({ groupId }) => { +export const GroupActivity: React.FC = ({ groupId }) => { const { t } = useTranslation(); const dispatch = useAppDispatch(); const group = useGroup(groupId); const members = useAppSelector((state) => selectGroupMembers(state, groupId)); - const logEntries = useAppSelector((state) => selectGroupLogs(state, groupId)); + const logs = useAppSelector((state) => selectGroupLogs(state, groupId)); const logLoadingStatus = useAppSelector((state) => selectGroupLogStatus(state, groupId)); - const [showAllLogs, setShowAllLogs] = useState(false); - const [message, setMessage] = useState(""); - useTitle(t("groups.log.tabTitle", "", { groupName: group?.name })); useEffect(() => { @@ -53,19 +39,6 @@ export const GroupLog: React.FC = ({ groupId }) => { }; }, [dispatch, groupId]); - const sendMessage = () => { - api.client.groups - .sendGroupMessage({ groupId, requestBody: { message } }) - .then((result) => { - console.log("sent message"); - setMessage(""); - }) - .catch((err) => { - console.log("error on send message", err); - toast.error(err); - }); - }; - const getMemberUsername = (member_id: number) => { const member = members.find((member) => member.user_id === member_id); if (member === undefined) { @@ -74,51 +47,16 @@ export const GroupLog: React.FC = ({ groupId }) => { return member.username; }; - const onKeyUp = (key: React.KeyboardEvent) => { - key.preventDefault(); - if (key.keyCode === 13) { - sendMessage(); - } - }; - - const log = showAllLogs ? logEntries : logEntries.filter((entry) => entry.type === "text-message"); - return ( {t("groups.log.header")} - setShowAllLogs(e.target.checked)} - /> - } - label={t("groups.log.showAllLogs")} - /> - setMessage(e.target.value)} - /> - - {logLoadingStatus === undefined || logLoadingStatus === "loading" ? ( ) : ( - log.map((logEntry) => ( + logs.map((logEntry) => ( = ({ group }) => { )} - @@ -232,7 +232,7 @@ export const SettingsForm: React.FC = ({ group }) => { {t("groups.settings.leaveGroup")} - {t("groups.settings.leaveGroupConfirm", "", { group })} + {t("groups.settings.leaveGroupConfirm", { group })} diff --git a/frontend/libs/translations/src/lib/de.ts b/frontend/libs/translations/src/lib/de.ts index d4f3788..eb824a8 100644 --- a/frontend/libs/translations/src/lib/de.ts +++ b/frontend/libs/translations/src/lib/de.ts @@ -80,10 +80,8 @@ const translations = { noGroups: "Keine Gruppen", }, log: { - tabTitle: "{{groupName}} - Protokoll", - header: "Gruppenprotokoll", - showAllLogs: "Alle Protokolle anzeigen", - writeAMessage: "Schreiben Sie eine Nachricht an die Gruppe ...", + tabTitle: "{{groupName}} - Aktivität", + header: "Aktivität", messageInfo: "von {{username}} am {{datetime}}", }, memberList: { diff --git a/frontend/libs/translations/src/lib/en.ts b/frontend/libs/translations/src/lib/en.ts index ce29191..d4ad4dc 100644 --- a/frontend/libs/translations/src/lib/en.ts +++ b/frontend/libs/translations/src/lib/en.ts @@ -75,10 +75,8 @@ const translations = { noGroups: "No Groups", }, log: { - tabTitle: "{{groupName}} - Log", - header: "Group Log", - showAllLogs: "Show all logs", - writeAMessage: "Write a message to the group ...", + tabTitle: "{{groupName}} - Activity", + header: "Group Activity", messageInfo: "by {{username}} on {{datetime}}", }, memberList: { From d139a951a156946d0633cba1736f3c27fc7e6259 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Loipf=C3=BChrer?= Date: Sun, 8 Sep 2024 13:38:23 +0200 Subject: [PATCH 4/9] fix(web): fix line breaks in currency values --- .../apps/web/src/hooks/useFormatCurrency.ts | 8 +- .../src/pages/accounts/BalanceBarGraph.tsx | 105 ++++++++++++++++++ .../apps/web/src/pages/accounts/Balances.tsx | 102 +---------------- 3 files changed, 115 insertions(+), 100 deletions(-) create mode 100644 frontend/apps/web/src/pages/accounts/BalanceBarGraph.tsx diff --git a/frontend/apps/web/src/hooks/useFormatCurrency.ts b/frontend/apps/web/src/hooks/useFormatCurrency.ts index c06b97c..bab6c61 100644 --- a/frontend/apps/web/src/hooks/useFormatCurrency.ts +++ b/frontend/apps/web/src/hooks/useFormatCurrency.ts @@ -1,7 +1,13 @@ import * as React from "react"; +const formatDef = new Intl.NumberFormat("de", { + currency: "EUR", + style: "currency", + minimumFractionDigits: 2, + maximumFractionDigits: 2, +}); export const useFormatCurrency = () => { return React.useCallback((value: number, currencySymbol: string) => { - return `${value.toFixed(2)} ${currencySymbol}`; + return formatDef.format(value).replace("€", currencySymbol); }, []); }; diff --git a/frontend/apps/web/src/pages/accounts/BalanceBarGraph.tsx b/frontend/apps/web/src/pages/accounts/BalanceBarGraph.tsx new file mode 100644 index 0000000..6c1d9ae --- /dev/null +++ b/frontend/apps/web/src/pages/accounts/BalanceBarGraph.tsx @@ -0,0 +1,105 @@ +import * as React from "react"; +import { useFormatCurrency } from "@/hooks"; +import { useAppSelector } from "@/store"; +import { selectAccountBalances, useSortedAccounts } from "@abrechnung/redux"; +import { Theme, useMediaQuery } from "@mui/material"; +import { useTheme } from "@mui/material/styles"; +import { useNavigate } from "react-router-dom"; +import { Bar, BarChart, Cell, LabelList, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts"; +import { CategoricalChartFunc } from "recharts/types/chart/generateCategoricalChart"; +import { Group } from "@abrechnung/api"; + +export type BalanceBarGraphProps = { + group: Group; +}; + +type Data = { + name: string; + id: number; + balance: number; + totalPaid: number; + totalConsumed: number; +}; + +export const BalanceBarGraph: React.FC = ({ group }) => { + const formatCurrency = useFormatCurrency(); + const theme: Theme = useTheme(); + const isSmallScreen = useMediaQuery(theme.breakpoints.down("sm")); + const navigate = useNavigate(); + + const personalAccounts = useSortedAccounts(group.id, "name", "personal"); + const balances = useAppSelector((state) => selectAccountBalances(state, group.id)); + + const colorGreen = theme.palette.mode === "light" ? theme.palette.success.light : theme.palette.success.dark; + const colorRed = theme.palette.mode === "light" ? theme.palette.error.light : theme.palette.error.dark; + + const roundTwoDecimals = (val: number) => +val.toFixed(2); + + const chartData: Data[] = personalAccounts.map((account) => { + const balance = balances[account.id]; + return { + name: account.name, + balance: roundTwoDecimals(balance?.balance ?? 0), + totalPaid: roundTwoDecimals(balance?.totalPaid ?? 0), + totalConsumed: roundTwoDecimals(balance?.totalConsumed ?? 0), + id: account.id, + }; + }); + + const chartHeight = Object.keys(balances).length * 30 + 100; + + // TODO determine the rendered width of the account names and take the maximum + const yaxiswidth = isSmallScreen + ? Math.max(Math.max(...personalAccounts.map((account) => account.name.length)), 20) + : Math.max(...personalAccounts.map((account) => account.name.length)) * 7 + 5; + + const handleBarClick: CategoricalChartFunc = (data) => { + const id = data.activePayload?.[0].payload.id; + navigate(`/groups/${group.id}/accounts/${id}`); + }; + + return ( +
+ + + + + formatCurrency(parseFloat(String(label)), group.currency_symbol)} + labelStyle={{ + color: theme.palette.text.primary, + }} + itemStyle={{ + color: theme.palette.text.primary, + }} + contentStyle={{ + backgroundColor: theme.palette.background.paper, + borderColor: theme.palette.divider, + borderRadius: theme.shape.borderRadius, + }} + /> + + {chartData.map((entry, index) => { + return = 0 ? colorGreen : colorRed} />; + })} + formatCurrency((entry as Data).balance, group.currency_symbol)} + position="insideLeft" + fill={theme.palette.text.primary} + /> + + + +
+ ); +}; diff --git a/frontend/apps/web/src/pages/accounts/Balances.tsx b/frontend/apps/web/src/pages/accounts/Balances.tsx index 5c399a3..59d63f6 100644 --- a/frontend/apps/web/src/pages/accounts/Balances.tsx +++ b/frontend/apps/web/src/pages/accounts/Balances.tsx @@ -21,28 +21,18 @@ import { import { useTheme } from "@mui/material/styles"; import React, { useState } from "react"; import { useTranslation } from "react-i18next"; -import { Navigate, Link as RouterLink, useNavigate } from "react-router-dom"; -import { Bar, BarChart, Cell, LabelList, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts"; -import { CategoricalChartFunc } from "recharts/types/chart/generateCategoricalChart"; +import { Navigate, Link as RouterLink } from "react-router-dom"; +import { BalanceBarGraph } from "./BalanceBarGraph"; interface Props { groupId: number; } -type Data = { - name: string; - id: number; - balance: number; - totalPaid: number; - totalConsumed: number; -}; - export const Balances: React.FC = ({ groupId }) => { const { t } = useTranslation(); const formatCurrency = useFormatCurrency(); const theme: Theme = useTheme(); const isSmallScreen = useMediaQuery(theme.breakpoints.down("sm")); - const navigate = useNavigate(); const group = useGroup(groupId); const personalAccounts = useSortedAccounts(groupId, "name", "personal"); @@ -51,8 +41,6 @@ export const Balances: React.FC = ({ groupId }) => { const [selectedTab, setSelectedTab] = useState("1"); - const colorGreen = theme.palette.mode === "light" ? theme.palette.success.light : theme.palette.success.dark; - const colorRed = theme.palette.mode === "light" ? theme.palette.error.light : theme.palette.error.dark; const colorGreenInverted = theme.palette.mode === "dark" ? theme.palette.success.light : theme.palette.success.dark; const colorRedInverted = theme.palette.mode === "dark" ? theme.palette.error.light : theme.palette.error.dark; @@ -62,19 +50,6 @@ export const Balances: React.FC = ({ groupId }) => { return ; } - const roundTwoDecimals = (val: number) => +val.toFixed(2); - - const chartData: Data[] = personalAccounts.map((account) => { - const balance = balances[account.id]; - return { - name: account.name, - balance: roundTwoDecimals(balance?.balance ?? 0), - totalPaid: roundTwoDecimals(balance?.totalPaid ?? 0), - totalConsumed: roundTwoDecimals(balance?.totalConsumed ?? 0), - id: account.id, - }; - }); - const unbalancedClearingAccounts = clearingAccounts .filter((account) => balances[account.id]?.balance !== 0) .map((account) => { @@ -85,18 +60,6 @@ export const Balances: React.FC = ({ groupId }) => { }; }); - const chartHeight = Object.keys(balances).length * 30 + 100; - - // TODO determine the rendered width of the account names and take the maximum - const yaxiswidth = isSmallScreen - ? Math.max(Math.max(...personalAccounts.map((account) => account.name.length)), 20) - : Math.max(...personalAccounts.map((account) => account.name.length)) * 7 + 5; - - const handleBarClick: CategoricalChartFunc = (data) => { - const id = data.activePayload?.[0].payload.id; - navigate(`/groups/${group.id}/accounts/${id}`); - }; - return ( @@ -151,66 +114,7 @@ export const Balances: React.FC = ({ groupId }) => { ))}
) : ( -
- - - - - - formatCurrency(parseFloat(String(label)), group.currency_symbol) - } - labelStyle={{ - color: theme.palette.text.primary, - }} - itemStyle={{ - color: theme.palette.text.primary, - }} - contentStyle={{ - backgroundColor: theme.palette.background.paper, - borderColor: theme.palette.divider, - borderRadius: theme.shape.borderRadius, - }} - /> - - {chartData.map((entry, index) => { - return ( - = 0 ? colorGreen : colorRed} - /> - ); - })} - - formatCurrency((entry as Data).balance, group.currency_symbol) - } - position="insideLeft" - fill={theme.palette.text.primary} - /> - - - -
+ )} From a708409fcbdd7ff28ae446061689ea78bb134e9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Loipf=C3=BChrer?= Date: Sun, 8 Sep 2024 17:00:53 +0200 Subject: [PATCH 5/9] fix(web): switch settings form to react-hook-form to get working again --- .../src/components/DisabledFormTextField.tsx | 27 ++ .../apps/web/src/components/FormTextField.tsx | 26 ++ frontend/apps/web/src/components/index.ts | 2 + .../pages/groups/settings/SettingsForm.tsx | 289 +++++++----------- frontend/package-lock.json | 25 ++ frontend/package.json | 2 + 6 files changed, 192 insertions(+), 179 deletions(-) create mode 100644 frontend/apps/web/src/components/DisabledFormTextField.tsx create mode 100644 frontend/apps/web/src/components/FormTextField.tsx diff --git a/frontend/apps/web/src/components/DisabledFormTextField.tsx b/frontend/apps/web/src/components/DisabledFormTextField.tsx new file mode 100644 index 0000000..6b9b87d --- /dev/null +++ b/frontend/apps/web/src/components/DisabledFormTextField.tsx @@ -0,0 +1,27 @@ +import * as React from "react"; +import { Control, Controller } from "react-hook-form"; +import { TextFieldProps } from "@mui/material"; +import { DisabledTextField } from "./style"; + +export type DisabledFormTextFieldProps = Omit & { + name: string; + control: Control; +}; + +export const DisabledFormTextField = ({ name, control, ...props }: DisabledFormTextFieldProps) => { + return ( + ( + + )} + /> + ); +}; diff --git a/frontend/apps/web/src/components/FormTextField.tsx b/frontend/apps/web/src/components/FormTextField.tsx new file mode 100644 index 0000000..d21c86b --- /dev/null +++ b/frontend/apps/web/src/components/FormTextField.tsx @@ -0,0 +1,26 @@ +import * as React from "react"; +import { Control, Controller } from "react-hook-form"; +import { TextField, TextFieldProps } from "@mui/material"; + +export type FormTextFieldProps = Omit & { + name: string; + control: Control; +}; + +export const FormTextField = ({ name, control, ...props }: FormTextFieldProps) => { + return ( + ( + + )} + /> + ); +}; diff --git a/frontend/apps/web/src/components/index.ts b/frontend/apps/web/src/components/index.ts index 85e83ef..ae2f19a 100644 --- a/frontend/apps/web/src/components/index.ts +++ b/frontend/apps/web/src/components/index.ts @@ -5,3 +5,5 @@ export * from "./TagSelector"; export * from "./AccountSelect"; export * from "./TextInput"; export * from "./NumericInput"; +export * from "./FormTextField"; +export * from "./DisabledFormTextField"; diff --git a/frontend/apps/web/src/pages/groups/settings/SettingsForm.tsx b/frontend/apps/web/src/pages/groups/settings/SettingsForm.tsx index 3a97bd9..fc7a774 100644 --- a/frontend/apps/web/src/pages/groups/settings/SettingsForm.tsx +++ b/frontend/apps/web/src/pages/groups/settings/SettingsForm.tsx @@ -1,29 +1,17 @@ -import * as React from "react"; -import { leaveGroup, updateGroup, useCurrentUserPermissions } from "@abrechnung/redux"; -import { Cancel, Edit, Save } from "@mui/icons-material"; -import { - Alert, - Button, - Checkbox, - Dialog, - DialogActions, - DialogContent, - DialogContentText, - DialogTitle, - FormGroup, - Grid, - LinearProgress, -} from "@mui/material"; -import { Form, Formik, FormikHelpers } from "formik"; -import { useNavigate } from "react-router-dom"; -import { toast } from "react-toastify"; -import { z } from "zod"; -import { DisabledFormControlLabel, DisabledTextField } from "@/components/style/DisabledTextField"; +import { DisabledFormControlLabel } from "@/components/style/DisabledTextField"; import { api } from "@/core/api"; import { useAppDispatch } from "@/store"; -import { toFormikValidationSchema } from "@abrechnung/utils"; -import { useTranslation } from "react-i18next"; import { Group } from "@abrechnung/api"; +import { updateGroup, useCurrentUserPermissions } from "@abrechnung/redux"; +import { Cancel, Edit, Save } from "@mui/icons-material"; +import { Alert, Button, Checkbox, FormGroup, Grid } from "@mui/material"; +import * as React from "react"; +import { useTranslation } from "react-i18next"; +import { toast } from "react-toastify"; +import { z } from "zod"; +import { Controller, SubmitHandler, useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { DisabledFormTextField } from "@/components"; type SettingsFormProps = { group: Group; @@ -41,9 +29,7 @@ type FormValues = z.infer; export const SettingsForm: React.FC = ({ group }) => { const { t } = useTranslation(); - const [showLeaveModal, setShowLeaveModal] = React.useState(false); const dispatch = useAppDispatch(); - const navigate = useNavigate(); const permissions = useCurrentUserPermissions(group.id); @@ -57,7 +43,18 @@ export const SettingsForm: React.FC = ({ group }) => { setIsEditing(false); }; - const handleSubmit = (values: FormValues, { setSubmitting }: FormikHelpers) => { + const { control, handleSubmit } = useForm({ + resolver: zodResolver(validationSchema), + defaultValues: { + name: group.name, + description: group.description, + terms: group.terms, + currency_symbol: group.currency_symbol, + addUserAccountOnJoin: group.add_user_account_on_join, + }, + }); + + const onSubmit: SubmitHandler = (values: FormValues) => { if (!group) { return; } @@ -76,21 +73,8 @@ export const SettingsForm: React.FC = ({ group }) => { ) .unwrap() .then(() => { - setSubmitting(false); setIsEditing(false); }) - .catch((err) => { - setSubmitting(false); - toast.error(err); - }); - }; - - const confirmLeaveGroup = () => { - dispatch(leaveGroup({ groupId: group.id, api })) - .unwrap() - .then(() => { - navigate("/"); - }) .catch((err) => { toast.error(err); }); @@ -101,149 +85,96 @@ export const SettingsForm: React.FC = ({ group }) => { } return ( - <> - - {({ values, handleBlur, handleChange, handleSubmit, isSubmitting }) => ( -
- + + - - + + + + ( + + )} /> - - - - } - label={t("groups.settings.autoAddAccounts")} - /> - + } + label={t("groups.settings.autoAddAccounts")} + /> + - {isSubmitting && } - -
- {permissions.can_write && isEditing && ( - <> - - - - )} - {permissions.can_write && !isEditing && ( - - )} -
- + -
- - )} -
- setShowLeaveModal(false)}> - {t("groups.settings.leaveGroup")} - - - {t("groups.settings.leaveGroupConfirm", { group })} - - - - - - - - + + )} + {permissions.can_write && !isEditing && ( + + )} + + + ); }; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index d5c8354..d537946 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -12,6 +12,7 @@ "@date-io/luxon": "^3.0.0", "@emotion/react": "11.13.0", "@emotion/styled": "11.13.0", + "@hookform/resolvers": "^3.9.0", "@mui/icons-material": "^5.16.6", "@mui/lab": "^5.0.0-alpha.173", "@mui/material": "^5.16.6", @@ -44,6 +45,7 @@ "multer": "^1.4.5-lts.1", "react": "18.2.0", "react-dom": "18.2.0", + "react-hook-form": "^7.53.0", "react-i18next": "^15.0.0", "react-native": "0.74.5", "react-native-gesture-handler": "~2.18.1", @@ -4364,6 +4366,14 @@ "@hapi/hoek": "^9.0.0" } }, + "node_modules/@hookform/resolvers": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.9.0.tgz", + "integrity": "sha512-bU0Gr4EepJ/EQsH/IwEzYLsT/PEj5C0ynLQ4m+GSHS+xKH4TfSelhluTgOaoc4kA5s7eCsQbM4wvZLzELmWzUg==", + "peerDependencies": { + "react-hook-form": "^7.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "dev": true, @@ -27410,6 +27420,21 @@ "react": ">=17.0.0" } }, + "node_modules/react-hook-form": { + "version": "7.53.0", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.53.0.tgz", + "integrity": "sha512-M1n3HhqCww6S2hxLxciEXy2oISPnAzxY7gvwVPrtlczTM/1dDadXgUxDpHMrMTblDOcm/AXtXxHwZ3jpg1mqKQ==", + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18 || ^19" + } + }, "node_modules/react-i18next": { "version": "15.0.0", "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.0.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 6b02a34..507df8a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -12,6 +12,7 @@ "@date-io/luxon": "^3.0.0", "@emotion/react": "11.13.0", "@emotion/styled": "11.13.0", + "@hookform/resolvers": "^3.9.0", "@mui/icons-material": "^5.16.6", "@mui/lab": "^5.0.0-alpha.173", "@mui/material": "^5.16.6", @@ -44,6 +45,7 @@ "multer": "^1.4.5-lts.1", "react": "18.2.0", "react-dom": "18.2.0", + "react-hook-form": "^7.53.0", "react-i18next": "^15.0.0", "react-native": "0.74.5", "react-native-gesture-handler": "~2.18.1", From 7f0d2ce67f68e60a7844dba9fed0e108926ed888 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Loipf=C3=BChrer?= Date: Sun, 8 Sep 2024 18:00:48 +0200 Subject: [PATCH 6/9] feat: implement group archiving --- abrechnung/application/accounts.py | 80 +- abrechnung/application/groups.py | 72 +- abrechnung/application/transactions.py | 22 +- abrechnung/core/auth.py | 16 +- abrechnung/core/decorators.py | 83 + .../revisions/0018_archivable_groups.sql | 9 + abrechnung/domain/groups.py | 2 + abrechnung/http/routers/accounts.py | 20 +- abrechnung/http/routers/groups.py | 34 +- abrechnung/http/routers/transactions.py | 18 +- api/openapi.json | 192 +- .../mobile/src/navigation/DrawerContent.tsx | 2 +- .../apps/mobile/src/navigation/Navigation.tsx | 2 +- .../TransactionList/TransactionList.tsx | 6 +- .../src/screens/groups/AccountDetail.tsx | 8 +- .../mobile/src/screens/groups/AccountEdit.tsx | 8 +- .../mobile/src/screens/groups/AccountList.tsx | 6 +- .../src/screens/groups/TransactionDetail.tsx | 23 +- .../authenticated-layout/SidebarGroupList.tsx | 6 +- .../components/GroupArchivedDisclaimer.tsx | 18 + .../accounts/AccountTransactionList.tsx | 2 +- .../accounts/BalanceHistoryGraph.tsx | 10 +- frontend/apps/web/src/components/index.ts | 1 + .../apps/web/src/hooks/useFormatCurrency.ts | 1 + .../accounts/AccountDetail/AccountInfo.tsx | 8 +- .../apps/web/src/pages/accounts/Balances.tsx | 27 +- .../ClearingAccountList.tsx | 14 +- .../ClearingAccountListItem.tsx | 28 +- .../PersonalAccountList.tsx | 18 +- .../PersonalAccountListItem.tsx | 16 +- .../apps/web/src/pages/groups/GroupList.tsx | 110 +- .../groups/settings/GroupSettingsPage.tsx | 168 +- .../TransactionDetail/TransactionActions.tsx | 9 +- .../TransactionList/TransactionList.tsx | 14 +- .../TransactionList/TransactionListItem.tsx | 2 +- frontend/libs/api/src/lib/generated/Client.ts | 31 +- .../api/src/lib/generated/core/ApiError.ts | 8 +- .../lib/generated/core/ApiRequestOptions.ts | 4 +- .../api/src/lib/generated/core/ApiResult.ts | 2 +- .../src/lib/generated/core/BaseHttpRequest.ts | 9 +- .../lib/generated/core/CancelablePromise.ts | 19 +- .../lib/generated/core/FetchHttpRequest.ts | 13 +- .../api/src/lib/generated/core/OpenAPI.ts | 12 +- .../api/src/lib/generated/core/request.ts | 117 +- frontend/libs/api/src/lib/generated/index.ts | 108 +- .../src/lib/generated/models/AccountType.ts | 5 +- .../lib/generated/models/Body_get_token.ts | 10 +- .../generated/models/ChangeEmailPayload.ts | 4 +- .../generated/models/ChangePasswordPayload.ts | 4 +- .../lib/generated/models/ClearingAccount.ts | 4 +- .../models/ConfirmEmailChangePayload.ts | 4 +- .../models/ConfirmPasswordRecoveryPayload.ts | 4 +- .../models/ConfirmRegistrationPayload.ts | 4 +- .../generated/models/CreateInvitePayload.ts | 4 +- .../generated/models/DeleteSessionPayload.ts | 4 +- .../lib/generated/models/FileAttachment.ts | 10 +- .../api/src/lib/generated/models/Group.ts | 6 +- .../src/lib/generated/models/GroupInvite.ts | 6 +- .../api/src/lib/generated/models/GroupLog.ts | 6 +- .../src/lib/generated/models/GroupMember.ts | 6 +- .../src/lib/generated/models/GroupMessage.ts | 4 +- .../src/lib/generated/models/GroupPayload.ts | 4 +- .../src/lib/generated/models/GroupPreview.ts | 4 +- .../generated/models/HTTPValidationError.ts | 7 +- .../src/lib/generated/models/LoginPayload.ts | 4 +- .../src/lib/generated/models/NewAccount.ts | 11 +- .../api/src/lib/generated/models/NewFile.ts | 4 +- .../lib/generated/models/NewTransaction.ts | 11 +- .../models/NewTransactionPosition.ts | 4 +- .../lib/generated/models/PersonalAccount.ts | 6 +- .../generated/models/PreviewGroupPayload.ts | 4 +- .../models/RecoverPasswordPayload.ts | 4 +- .../lib/generated/models/RegisterPayload.ts | 6 +- .../lib/generated/models/RegisterResponse.ts | 4 +- .../generated/models/RenameSessionPayload.ts | 4 +- .../api/src/lib/generated/models/Session.ts | 6 +- .../api/src/lib/generated/models/Token.ts | 4 +- .../src/lib/generated/models/Transaction.ts | 11 +- .../generated/models/TransactionPosition.ts | 4 +- .../lib/generated/models/TransactionType.ts | 5 +- .../src/lib/generated/models/UpdateFile.ts | 4 +- .../models/UpdateGroupMemberPayload.ts | 4 +- .../models/UpdatePositionsPayload.ts | 7 +- .../lib/generated/models/UpdateTransaction.ts | 15 +- .../libs/api/src/lib/generated/models/User.ts | 7 +- .../lib/generated/models/ValidationError.ts | 6 +- .../lib/generated/models/VersionResponse.ts | 4 +- frontend/libs/api/src/lib/generated/schema.ts | 3065 +++++++++-------- .../lib/generated/services/AccountsService.ts | 92 +- .../src/lib/generated/services/AuthService.ts | 185 +- .../lib/generated/services/CommonService.ts | 15 +- .../lib/generated/services/GroupsService.ts | 267 +- .../generated/services/TransactionsService.ts | 127 +- frontend/libs/redux/src/index.ts | 1 + .../redux/src/lib/accounts/accountSlice.ts | 16 +- .../lib/context/AbrechnungUpdateProvider.tsx | 16 +- frontend/libs/redux/src/lib/groups/actions.ts | 14 + .../libs/redux/src/lib/groups/groupSlice.ts | 14 +- frontend/libs/redux/src/lib/hooks/index.ts | 1 + .../src/lib/hooks/useIsGroupWritable.tsx | 13 + .../src/lib/transactions/transactionSlice.ts | 10 +- frontend/libs/translations/src/lib/en.ts | 9 + frontend/nx.json | 4 +- 103 files changed, 3136 insertions(+), 2330 deletions(-) create mode 100644 abrechnung/core/decorators.py create mode 100644 abrechnung/database/revisions/0018_archivable_groups.sql create mode 100644 frontend/apps/web/src/components/GroupArchivedDisclaimer.tsx create mode 100644 frontend/libs/redux/src/lib/hooks/index.ts create mode 100644 frontend/libs/redux/src/lib/hooks/useIsGroupWritable.tsx diff --git a/abrechnung/application/accounts.py b/abrechnung/application/accounts.py index 2f45822..ad55023 100644 --- a/abrechnung/application/accounts.py +++ b/abrechnung/application/accounts.py @@ -1,9 +1,12 @@ -from datetime import datetime, timezone from typing import Optional, Union import asyncpg from abrechnung.core.auth import check_group_permissions, create_group_log +from abrechnung.core.decorators import ( + requires_group_permissions, + with_group_last_changed_update, +) from abrechnung.core.errors import InvalidCommand, NotFoundError from abrechnung.core.service import Service from abrechnung.domain.accounts import ( @@ -13,6 +16,7 @@ NewAccount, PersonalAccount, ) +from abrechnung.domain.groups import GroupMember from abrechnung.domain.users import User from abrechnung.framework.database import Connection from abrechnung.framework.decorators import with_db_connection, with_db_transaction @@ -148,10 +152,10 @@ async def _account_clearing_shares_check( return group_id, revision_id @with_db_transaction + @requires_group_permissions() async def list_accounts(self, *, conn: Connection, user: User, group_id: int) -> list[Account]: - await check_group_permissions(conn=conn, group_id=group_id, user=user) rows = await conn.fetch( - "select * " "from full_account_state_valid_at(now()) " "where group_id = $1", + "select * from full_account_state_valid_at(now()) where group_id = $1", group_id, ) return [ @@ -164,10 +168,11 @@ async def list_accounts(self, *, conn: Connection, user: User, group_id: int) -> ] @with_db_connection + @requires_group_permissions() async def get_account(self, *, conn: Connection, user: User, account_id: int) -> Account: await self._check_account_permissions(conn=conn, user=user, account_id=account_id) row = await conn.fetchrow( - "select * " "from full_account_state_valid_at(now()) " "where id = $1", + "select * from full_account_state_valid_at(now()) where id = $1", account_id, ) if row["type"] == AccountType.clearing.value: @@ -186,21 +191,31 @@ async def _add_tags_to_revision( return for tag_id in tag_ids: await conn.execute( - "insert into account_to_tag (account_id, revision_id, tag_id) " "values ($1, $2, $3)", + "insert into account_to_tag (account_id, revision_id, tag_id) values ($1, $2, $3)", account_id, revision_id, tag_id, ) - async def _create_account(self, *, conn: asyncpg.Connection, user: User, group_id: int, account: NewAccount) -> int: + @with_db_transaction + @requires_group_permissions(requires_write=True) + @with_group_last_changed_update + async def create_account( + self, + *, + conn: Connection, + user: User, + group_id: int, + account: NewAccount, + group_membership: GroupMember, + ) -> int: if account.clearing_shares and account.type != AccountType.clearing: raise InvalidCommand( f"'{account.type.value}' accounts cannot have associated settlement distribution shares" ) - can_write, is_owner = await check_group_permissions(conn=conn, group_id=group_id, user=user, can_write=True) if account.owning_user_id is not None: - if not is_owner and account.owning_user_id != user.id: + if not group_membership.is_owner and account.owning_user_id != user.id: raise PermissionError(f"only group owners can associate others with accounts") account_id = await conn.fetchval( @@ -250,32 +265,19 @@ async def _create_account(self, *, conn: asyncpg.Connection, user: User, group_i return account_id @with_db_transaction - async def create_account( + @with_group_last_changed_update + async def update_account( self, *, conn: Connection, user: User, - group_id: int, - account: NewAccount, - ) -> int: - return await self._create_account( - conn=conn, - user=user, - group_id=group_id, - account=account, - ) - - async def _update_account( - self, - conn: asyncpg.Connection, - user: User, account_id: int, account: NewAccount, ): group_id, account_type = await self._check_account_permissions( conn=conn, user=user, account_id=account_id, can_write=True ) - can_write, is_owner = await check_group_permissions(conn=conn, group_id=group_id, user=user, can_write=True) + membership = await check_group_permissions(conn=conn, group_id=group_id, user=user, can_write=True) if account.clearing_shares and account_type != AccountType.clearing.value: raise InvalidCommand(f"'{account_type}' accounts cannot have associated settlement distribution shares") @@ -287,12 +289,12 @@ async def _update_account( ) if account.owning_user_id is not None: - if not is_owner and account.owning_user_id != user.id: + if not membership.is_owner and account.owning_user_id != user.id: raise PermissionError(f"only group owners can associate others with accounts") elif ( committed_account["owning_user_id"] is not None and committed_account["owning_user_id"] != user.id - and not is_owner + and not membership.is_owner ): raise PermissionError(f"only group owners can remove other users as account owners") @@ -334,22 +336,7 @@ async def _update_account( await self._commit_revision(conn=conn, revision_id=revision_id) @with_db_transaction - async def update_account( - self, - *, - conn: Connection, - user: User, - account_id: int, - account: NewAccount, - ): - return await self._update_account( - conn=conn, - user=user, - account_id=account_id, - account=account, - ) - - @with_db_transaction + @with_group_last_changed_update async def delete_account( self, *, @@ -368,12 +355,13 @@ async def delete_account( # TODO: FIXME move this check into the database has_shares = await conn.fetchval( - "select 1 " "from transaction_state_valid_at() t " "where not deleted and $1 = any(involved_accounts)", + "select exists (select from transaction_state_valid_at() t " + "where not deleted and $1 = any(involved_accounts))", account_id, ) has_clearing_shares = await conn.fetchval( - "select 1 " "from account_state_valid_at() a " "where not deleted and $1 = any(involved_accounts)", + "select exists(select from account_state_valid_at() a where not deleted and $1 = any(involved_accounts))", account_id, ) @@ -402,7 +390,7 @@ async def delete_account( raise InvalidCommand(f"Cannot delete an already deleted account") has_clearing_shares = await conn.fetchval( - "select 1 " "from account_state_valid_at() p " "where not p.deleted and $1 = any(p.involved_accounts)", + "select exists (select from account_state_valid_at() p where not p.deleted and $1 = any(p.involved_accounts))", account_id, ) @@ -410,7 +398,7 @@ async def delete_account( raise InvalidCommand(f"Cannot delete an account that is references by another clearing account") revision_id = await conn.fetchval( - "insert into account_revision (user_id, account_id) " "values ($1, $2) returning id", + "insert into account_revision (user_id, account_id) values ($1, $2) returning id", user.id, account_id, ) diff --git a/abrechnung/application/groups.py b/abrechnung/application/groups.py index 808fc43..38b530b 100644 --- a/abrechnung/application/groups.py +++ b/abrechnung/application/groups.py @@ -2,7 +2,11 @@ import asyncpg -from abrechnung.core.auth import check_group_permissions, create_group_log +from abrechnung.core.auth import create_group_log +from abrechnung.core.decorators import ( + requires_group_permissions, + with_group_last_changed_update, +) from abrechnung.core.errors import InvalidCommand, NotFoundError from abrechnung.core.service import Service from abrechnung.domain.accounts import AccountType @@ -69,6 +73,7 @@ async def create_group( return group_id @with_db_transaction + @requires_group_permissions(requires_write=True) async def create_invite( self, *, @@ -83,7 +88,6 @@ async def create_invite( if user.is_guest_user: raise PermissionError(f"guest users are not allowed to create group invites") - await check_group_permissions(conn=conn, group_id=group_id, user=user, can_write=True) await create_group_log(conn=conn, group_id=group_id, user=user, type="invite-created") return await conn.fetchval( "insert into group_invite(group_id, description, created_by, valid_until, single_use, join_as_editor)" @@ -97,6 +101,7 @@ async def create_invite( ) @with_db_transaction + @requires_group_permissions(requires_write=True) async def delete_invite( self, *, @@ -105,7 +110,6 @@ async def delete_invite( group_id: int, invite_id: int, ): - await check_group_permissions(conn=conn, group_id=group_id, user=user, can_write=True) deleted_id = await conn.fetchval( "delete from group_invite where id = $1 and group_id = $2 returning id", invite_id, @@ -191,25 +195,22 @@ async def join_group(self, *, conn: Connection, user: User, invite_token: str) - async def list_groups(self, *, conn: Connection, user: User) -> list[Group]: return await conn.fetch_many( Group, - "select grp.id, grp.name, grp.description, grp.terms, grp.currency_symbol, grp.created_at, " - "grp.created_by, grp.add_user_account_on_join " - "from grp " - "join group_membership gm on grp.id = gm.group_id where gm.user_id = $1", + "select grp.* " "from grp " "join group_membership gm on grp.id = gm.group_id where gm.user_id = $1", user.id, ) @with_db_transaction + @requires_group_permissions() async def get_group(self, *, conn: Connection, user: User, group_id: int) -> Group: - await check_group_permissions(conn=conn, group_id=group_id, user=user) return await conn.fetch_one( Group, - "select id, name, description, terms, currency_symbol, created_at, created_by, add_user_account_on_join " - "from grp " - "where grp.id = $1", + "select * " "from grp " "where grp.id = $1", group_id, ) @with_db_transaction + @requires_group_permissions(requires_owner=True) + @with_group_last_changed_update async def update_group( self, *, @@ -222,7 +223,6 @@ async def update_group( add_user_account_on_join: bool, terms: str, ): - await check_group_permissions(conn=conn, group_id=group_id, user=user, is_owner=True) await conn.execute( "update grp set name = $2, description = $3, currency_symbol = $4, terms = $5, add_user_account_on_join = $6 " "where grp.id = $1", @@ -236,11 +236,13 @@ async def update_group( await create_group_log(conn=conn, group_id=group_id, user=user, type="group-updated") @with_db_transaction + @requires_group_permissions(requires_write=True) async def update_member_permissions( self, *, conn: Connection, user: User, + group_membership: GroupMember, group_id: int, member_id: int, can_write: bool, @@ -252,9 +254,6 @@ async def update_member_permissions( # not possible to have an owner without can_write can_write = can_write if not is_owner else True - user_can_write, user_is_owner = await check_group_permissions( - conn=conn, group_id=group_id, user=user, can_write=True - ) membership = await conn.fetchrow( "select is_owner, can_write from group_membership where group_id = $1 and user_id = $2", group_id, @@ -266,7 +265,7 @@ async def update_member_permissions( if membership["is_owner"] == is_owner and membership["can_write"] == can_write: # no changes return - if is_owner and not user_is_owner: + if is_owner and not group_membership.is_owner: raise PermissionError(f"group members cannot promote others to owner without being an owner") if membership["is_owner"]: @@ -324,9 +323,8 @@ async def update_member_permissions( ) @with_db_transaction + @requires_group_permissions(requires_owner=True) async def delete_group(self, *, conn: Connection, user: User, group_id: int): - await check_group_permissions(conn=conn, group_id=group_id, user=user, is_owner=True) - n_members = await conn.fetchval( "select count(user_id) from group_membership gm where gm.group_id = $1", group_id, @@ -337,9 +335,8 @@ async def delete_group(self, *, conn: Connection, user: User, group_id: int): await conn.execute("delete from grp where id = $1", group_id) @with_db_transaction + @requires_group_permissions() async def leave_group(self, *, conn: Connection, user: User, group_id: int): - await check_group_permissions(conn=conn, group_id=group_id, user=user) - n_members = await conn.fetchval( "select count(user_id) from group_membership gm where gm.group_id = $1", group_id, @@ -372,8 +369,8 @@ async def preview_group(self, *, conn: Connection, invite_token: str) -> GroupPr return group @with_db_transaction + @requires_group_permissions() async def list_invites(self, *, conn: Connection, user: User, group_id: int) -> list[GroupInvite]: - await check_group_permissions(conn=conn, group_id=group_id, user=user) return await conn.fetch_many( GroupInvite, "select id, case when created_by = $1 then token::text else null end as token, description, created_by, " @@ -385,8 +382,8 @@ async def list_invites(self, *, conn: Connection, user: User, group_id: int) -> ) @with_db_transaction + @requires_group_permissions() async def get_invite(self, *, conn: Connection, user: User, group_id: int, invite_id: int) -> GroupInvite: - await check_group_permissions(conn=conn, group_id=group_id, user=user) return await conn.fetch_one( GroupInvite, "select id, case when created_by = $1 then token::text else null end as token, description, created_by, " @@ -399,8 +396,8 @@ async def get_invite(self, *, conn: Connection, user: User, group_id: int, invit ) @with_db_transaction + @requires_group_permissions() async def list_members(self, *, conn: Connection, user: User, group_id: int) -> list[GroupMember]: - await check_group_permissions(conn=conn, group_id=group_id, user=user) return await conn.fetch_many( GroupMember, "select usr.id as user_id, usr.username, gm.is_owner, gm.can_write, gm.description, " @@ -412,8 +409,8 @@ async def list_members(self, *, conn: Connection, user: User, group_id: int) -> ) @with_db_transaction + @requires_group_permissions() async def get_member(self, *, conn: Connection, user: User, group_id: int, member_id: int) -> GroupMember: - await check_group_permissions(conn=conn, group_id=group_id, user=user) return await conn.fetch_one( GroupMember, "select usr.id as user_id, usr.username, gm.is_owner, gm.can_write, gm.description, " @@ -426,20 +423,39 @@ async def get_member(self, *, conn: Connection, user: User, group_id: int, membe ) @with_db_transaction + @requires_group_permissions() async def list_log(self, *, conn: Connection, user: User, group_id: int) -> list[GroupLog]: - await check_group_permissions(conn=conn, group_id=group_id, user=user) return await conn.fetch_many( GroupLog, - "select id, user_id, logged_at, type, message, affected " "from group_log " "where group_id = $1", + "select id, user_id, logged_at, type, message, affected from group_log where group_id = $1", group_id, ) @with_db_transaction + @requires_group_permissions(requires_write=True) + @with_group_last_changed_update async def send_group_message(self, *, conn: Connection, user: User, group_id: int, message: str): - await check_group_permissions(conn=conn, group_id=group_id, user=user, can_write=True) await conn.execute( - "insert into group_log (group_id, user_id, type, message) " "values ($1, $2, 'text-message', $3)", + "insert into group_log (group_id, user_id, type, message) values ($1, $2, 'text-message', $3)", group_id, user.id, message, ) + + @with_db_transaction + @requires_group_permissions(requires_owner=True) + @with_group_last_changed_update + async def archive_group(self, *, conn: Connection, user: User, group_id: int): + await conn.execute( + "update grp set archived = true where id = $1", + group_id, + ) + + @with_db_transaction + @requires_group_permissions(requires_owner=True) + @with_group_last_changed_update + async def unarchive_group(self, *, conn: Connection, user: User, group_id: int): + await conn.execute( + "update grp set archived = false where id = $1", + group_id, + ) diff --git a/abrechnung/application/transactions.py b/abrechnung/application/transactions.py index d2feeaf..3a0ccc2 100644 --- a/abrechnung/application/transactions.py +++ b/abrechnung/application/transactions.py @@ -5,7 +5,11 @@ import asyncpg from abrechnung.application.common import _get_or_create_tag_ids -from abrechnung.core.auth import check_group_permissions, create_group_log +from abrechnung.core.auth import create_group_log +from abrechnung.core.decorators import ( + requires_group_permissions, + with_group_last_changed_update, +) from abrechnung.core.errors import InvalidCommand, NotFoundError from abrechnung.core.service import Service from abrechnung.domain.transactions import ( @@ -54,6 +58,7 @@ async def _check_transaction_permissions( return result["group_id"] @with_db_transaction + @requires_group_permissions() async def list_transactions( self, *, @@ -63,8 +68,6 @@ async def list_transactions( min_last_changed: Optional[datetime] = None, additional_transactions: Optional[list[int]] = None, ) -> list[Transaction]: - await check_group_permissions(conn=conn, group_id=group_id, user=user) - if min_last_changed: # if a minimum last changed value is specified we must also return all transactions the current # user has pending changes with to properly sync state across different devices of the user @@ -81,7 +84,7 @@ async def list_transactions( else: transactions = await conn.fetch_many( Transaction, - "select * " "from full_transaction_state_valid_at(now()) " "where group_id = $1", + "select * from full_transaction_state_valid_at(now()) where group_id = $1", group_id, ) for transaction in transactions: @@ -94,7 +97,7 @@ async def get_transaction(self, *, conn: Connection, user: User, transaction_id: group_id = await self._check_transaction_permissions(conn=conn, user=user, transaction_id=transaction_id) transaction = await conn.fetch_one( Transaction, - "select * " "from full_transaction_state_valid_at(now()) " "where group_id = $1 and id = $2", + "select * from full_transaction_state_valid_at(now()) where group_id = $1 and id = $2", group_id, transaction_id, ) @@ -182,7 +185,6 @@ async def _create_transaction( group_id: int, transaction: NewTransaction, ) -> int: - await check_group_permissions(conn=conn, group_id=group_id, user=user) transaction_id = await conn.fetchval( "insert into transaction (group_id, type) values ($1, $2) returning id", group_id, @@ -250,6 +252,8 @@ async def _create_transaction( return transaction_id @with_db_transaction + @requires_group_permissions(requires_write=True) + @with_group_last_changed_update async def create_transaction( self, *, @@ -546,6 +550,8 @@ async def _update_transaction( await self._commit_revision(conn=conn, revision_id=revision_id) @with_db_transaction + @requires_group_permissions(requires_write=True) + @with_group_last_changed_update async def update_transaction( self, *, @@ -562,6 +568,8 @@ async def update_transaction( ) @with_db_transaction + @requires_group_permissions(requires_write=True) + @with_group_last_changed_update async def update_transaction_positions( self, *, @@ -589,6 +597,8 @@ async def update_transaction_positions( ) @with_db_transaction + @requires_group_permissions(requires_write=True) + @with_group_last_changed_update async def delete_transaction(self, *, conn: Connection, user: User, transaction_id: int): group_id = await self._check_transaction_permissions( conn=conn, diff --git a/abrechnung/core/auth.py b/abrechnung/core/auth.py index f393a54..6a532ff 100644 --- a/abrechnung/core/auth.py +++ b/abrechnung/core/auth.py @@ -1,3 +1,4 @@ +from abrechnung.domain.groups import GroupMember from abrechnung.domain.users import User from abrechnung.framework.database import Connection @@ -10,22 +11,25 @@ async def check_group_permissions( user: User, is_owner: bool = False, can_write: bool = False, -) -> tuple[bool, bool]: - membership = await conn.fetchrow( - "select is_owner, can_write from group_membership where group_id = $1 and user_id = $2", +) -> GroupMember: + membership = await conn.fetch_maybe_one( + GroupMember, + "select g.*, u.username from group_membership g " + "join usr u on g.user_id = u.id " + "where g.group_id = $1 and g.user_id = $2", group_id, user.id, ) if membership is None: raise NotFoundError(f"group not found") - if can_write and not (membership["is_owner"] or membership["can_write"]): + if can_write and not (membership.is_owner or membership.can_write): raise PermissionError(f"write access to group denied") - if is_owner and not membership["is_owner"]: + if is_owner and not membership.is_owner: raise PermissionError(f"owner access to group denied") - return membership["can_write"], membership["is_owner"] + return membership async def create_group_log( diff --git a/abrechnung/core/decorators.py b/abrechnung/core/decorators.py new file mode 100644 index 0000000..eba3799 --- /dev/null +++ b/abrechnung/core/decorators.py @@ -0,0 +1,83 @@ +from functools import wraps +from inspect import signature, Parameter +from typing import Awaitable, Callable, TypeVar + +from abrechnung.core.auth import check_group_permissions + +R = TypeVar("R") + + +def _add_arg_to_signature(original_func, new_func, name: str, annotation): + sig = signature(original_func) + if name in sig.parameters: + return + new_parameters = tuple(sig.parameters.values()) + (Parameter(name, kind=Parameter.KEYWORD_ONLY, annotation=annotation),) + sig = sig.replace(parameters=new_parameters) + new_func.__signature__ = sig # type: ignore + + +def requires_group_permissions( + requires_write: bool = False, requires_owner: bool = False +) -> Callable[[Callable[..., Awaitable[R]]], Callable[..., Awaitable[R]]]: + def f(func: Callable[..., Awaitable[R]]): + original_signature = signature(func) + + @wraps(func) + async def wrapper(*args, **kwargs): + if "conn" not in kwargs: + raise RuntimeError( + "requires_group_permissions needs a database connection, " + "with_db_transaction needs to be put before this decorator" + ) + + if "group_id" not in kwargs: + raise RuntimeError("requires_group_permissions requires 'group_id' to be a keyword argument") + + if "user" not in kwargs: + raise RuntimeError("requires_group_permissions requires 'user' to be a keyword argument") + + conn = kwargs["conn"] + user = kwargs["user"] + group_id = kwargs.pop("group_id") + group_membership = await check_group_permissions( + conn=conn, group_id=group_id, user=user, can_write=requires_write, is_owner=requires_owner + ) + if "group_membership" in original_signature.parameters: + kwargs["group_membership"] = group_membership + + if "group_id" in original_signature.parameters: + kwargs["group_id"] = group_id + + return await func(*args, **kwargs) + + _add_arg_to_signature(func, wrapper, "group_id", int) + + return wrapper + + return f + + +def with_group_last_changed_update(func: Callable[..., Awaitable[R]]) -> Callable[..., Awaitable[R]]: + original_signature = signature(func) + + @wraps(func) + async def wrapper(*args, **kwargs): + if "conn" not in kwargs: + raise RuntimeError( + "with_group_last_changed_update needs a database connection, " + "with_db_transaction needs to be put before this decorator" + ) + + if "group_id" not in kwargs: + raise RuntimeError("with_group_last_changed_update requires 'group_id' to be a keyword argument") + + conn = kwargs["conn"] + group_id = kwargs.pop("group_id") + await conn.execute("update grp set last_changed = now() where id = $1", group_id) + if "group_id" in original_signature.parameters: + kwargs["group_id"] = group_id + + return await func(*args, **kwargs) + _add_arg_to_signature(func, wrapper, "group_id", int) + + return wrapper diff --git a/abrechnung/database/revisions/0018_archivable_groups.sql b/abrechnung/database/revisions/0018_archivable_groups.sql new file mode 100644 index 0000000..d9d44e0 --- /dev/null +++ b/abrechnung/database/revisions/0018_archivable_groups.sql @@ -0,0 +1,9 @@ +-- revision: 2467f144 +-- requires: 04424b59 + +alter table grp add column archived boolean not null default false; + +alter table grp add column last_changed timestamptz; +update grp set last_changed = created_at; +alter table grp alter column last_changed set not null; +alter table grp alter column last_changed set default now(); diff --git a/abrechnung/domain/groups.py b/abrechnung/domain/groups.py index 5f2d700..b6d4222 100644 --- a/abrechnung/domain/groups.py +++ b/abrechnung/domain/groups.py @@ -33,6 +33,8 @@ class Group(BaseModel): add_user_account_on_join: bool created_at: datetime created_by: int + last_changed: datetime + archived: bool class GroupLog(BaseModel): diff --git a/abrechnung/http/routers/accounts.py b/abrechnung/http/routers/accounts.py index ac00973..5d19890 100644 --- a/abrechnung/http/routers/accounts.py +++ b/abrechnung/http/routers/accounts.py @@ -57,9 +57,13 @@ async def create_account( @router.get( - r"/v1/accounts/{account_id}", summary="fetch a group account", response_model=Account, operation_id="get_account" + r"/v1/groups/{group_id}/accounts/{account_id}", + summary="fetch a group account", + response_model=Account, + operation_id="get_account", ) async def get_account( + group_id: int, account_id: int, user: User = Depends(get_current_user), account_service: AccountService = Depends(get_account_service), @@ -68,15 +72,20 @@ async def get_account( @router.post( - r"/v1/accounts/{account_id}", summary="update an account", response_model=Account, operation_id="update_account" + r"/v1/groups/{group_id}/accounts/{account_id}", + summary="update an account", + response_model=Account, + operation_id="update_account", ) async def update_account( + group_id: int, account_id: int, payload: NewAccount, user: User = Depends(get_current_user), account_service: AccountService = Depends(get_account_service), ): await account_service.update_account( + group_id=group_id, user=user, account_id=account_id, account=payload, @@ -86,14 +95,19 @@ async def update_account( @router.delete( - r"/v1/accounts/{account_id}", summary="delete an account", response_model=Account, operation_id="delete_account" + r"/v1/groups/{group_id}/accounts/{account_id}", + summary="delete an account", + response_model=Account, + operation_id="delete_account", ) async def delete_account( + group_id: int, account_id: int, user: User = Depends(get_current_user), account_service: AccountService = Depends(get_account_service), ): await account_service.delete_account( + group_id=group_id, user=user, account_id=account_id, ) diff --git a/abrechnung/http/routers/groups.py b/abrechnung/http/routers/groups.py index 14ea256..f1683e7 100644 --- a/abrechnung/http/routers/groups.py +++ b/abrechnung/http/routers/groups.py @@ -1,5 +1,5 @@ from datetime import datetime, timezone -from typing import List, Optional +from typing import List from fastapi import APIRouter, Depends, status from pydantic import BaseModel @@ -307,3 +307,35 @@ async def delete_invite( group_id=group_id, invite_id=invite_id, ) + + +@router.post( + r"/v1/groups/{group_id}/archive", + summary="archive a group", + operation_id="archive_group", +) +async def archive_group( + group_id: int, + user: User = Depends(get_current_user), + group_service: GroupService = Depends(get_group_service), +): + await group_service.archive_group( + user=user, + group_id=group_id, + ) + + +@router.post( + r"/v1/groups/{group_id}/un-archive", + summary="un-archive a group", + operation_id="unarchive_group", +) +async def unarchive_group( + group_id: int, + user: User = Depends(get_current_user), + group_service: GroupService = Depends(get_group_service), +): + await group_service.unarchive_group( + user=user, + group_id=group_id, + ) diff --git a/abrechnung/http/routers/transactions.py b/abrechnung/http/routers/transactions.py index 5e57f82..9baf369 100644 --- a/abrechnung/http/routers/transactions.py +++ b/abrechnung/http/routers/transactions.py @@ -79,12 +79,13 @@ async def create_transaction( @router.get( - "/v1/transactions/{transaction_id}", + "/v1/groups/{group_id}/transactions/{transaction_id}", summary="get transaction details", response_model=Transaction, operation_id="get_transaction", ) async def get_transaction( + group_id: int, transaction_id: int, user: User = Depends(get_current_user), transaction_service: TransactionService = Depends(get_transaction_service), @@ -93,21 +94,20 @@ async def get_transaction( @router.post( - "/v1/transactions/{transaction_id}", + "/v1/groups/{group_id}/transactions/{transaction_id}", summary="update transaction details", response_model=Transaction, operation_id="update_transaction", ) async def update_transaction( + group_id: int, transaction_id: int, payload: UpdateTransaction, user: User = Depends(get_current_user), transaction_service: TransactionService = Depends(get_transaction_service), ): await transaction_service.update_transaction( - user=user, - transaction_id=transaction_id, - transaction=payload, + user=user, transaction_id=transaction_id, transaction=payload, group_id=group_id ) return await transaction_service.get_transaction(user=user, transaction_id=transaction_id) @@ -117,18 +117,20 @@ class UpdatePositionsPayload(BaseModel): @router.post( - "/v1/transactions/{transaction_id}/positions", + "/v1/groups/{group_id}/transactions/{transaction_id}/positions", summary="update transaction positions", response_model=Transaction, operation_id="update_transaction_positions", ) async def update_transaction_positions( + group_id: int, transaction_id: int, payload: UpdatePositionsPayload, user: User = Depends(get_current_user), transaction_service: TransactionService = Depends(get_transaction_service), ): await transaction_service.update_transaction_positions( + group_id=group_id, user=user, transaction_id=transaction_id, positions=payload.positions, @@ -137,17 +139,19 @@ async def update_transaction_positions( @router.delete( - "/v1/transactions/{transaction_id}", + "/v1/groups/{group_id}/transactions/{transaction_id}", summary="delete a transaction", response_model=Transaction, operation_id="delete_transaction", ) async def delete_transaction( + group_id: int, transaction_id: int, user: User = Depends(get_current_user), transaction_service: TransactionService = Depends(get_transaction_service), ): await transaction_service.delete_transaction( + group_id=group_id, user=user, transaction_id=transaction_id, ) diff --git a/api/openapi.json b/api/openapi.json index d3d3b7c..397e3f5 100644 --- a/api/openapi.json +++ b/api/openapi.json @@ -6,7 +6,7 @@ "name": "AGPL-3.0", "identifier": "AGPL-3.0" }, - "version": "0.10.1" + "version": "0.14.0" }, "paths": { "/api/v1/groups/{group_id}/transactions": { @@ -166,7 +166,7 @@ } } }, - "/api/v1/transactions/{transaction_id}": { + "/api/v1/groups/{group_id}/transactions/{transaction_id}": { "get": { "tags": [ "transactions" @@ -179,6 +179,15 @@ } ], "parameters": [ + { + "name": "group_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "title": "Group Id" + } + }, { "name": "transaction_id", "in": "path", @@ -233,6 +242,15 @@ } ], "parameters": [ + { + "name": "group_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "title": "Group Id" + } + }, { "name": "transaction_id", "in": "path", @@ -297,6 +315,15 @@ } ], "parameters": [ + { + "name": "group_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "title": "Group Id" + } + }, { "name": "transaction_id", "in": "path", @@ -340,7 +367,7 @@ } } }, - "/api/v1/transactions/{transaction_id}/positions": { + "/api/v1/groups/{group_id}/transactions/{transaction_id}/positions": { "post": { "tags": [ "transactions" @@ -353,6 +380,15 @@ } ], "parameters": [ + { + "name": "group_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "title": "Group Id" + } + }, { "name": "transaction_id", "in": "path", @@ -1302,6 +1338,114 @@ } } }, + "/api/v1/groups/{group_id}/archive": { + "post": { + "tags": [ + "groups" + ], + "summary": "archive a group", + "operationId": "archive_group", + "security": [ + { + "OAuth2PasswordBearer": [] + } + ], + "parameters": [ + { + "name": "group_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "title": "Group Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "401": { + "description": "unauthorized" + }, + "403": { + "description": "forbidden" + }, + "404": { + "description": "Not found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/api/v1/groups/{group_id}/un-archive": { + "post": { + "tags": [ + "groups" + ], + "summary": "un-archive a group", + "operationId": "unarchive_group", + "security": [ + { + "OAuth2PasswordBearer": [] + } + ], + "parameters": [ + { + "name": "group_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "title": "Group Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "401": { + "description": "unauthorized" + }, + "403": { + "description": "forbidden" + }, + "404": { + "description": "Not found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, "/api/v1/auth/token": { "post": { "tags": [ @@ -1901,7 +2045,7 @@ } } }, - "/api/v1/accounts/{account_id}": { + "/api/v1/groups/{group_id}/accounts/{account_id}": { "get": { "tags": [ "accounts" @@ -1914,6 +2058,15 @@ } ], "parameters": [ + { + "name": "group_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "title": "Group Id" + } + }, { "name": "account_id", "in": "path", @@ -1976,6 +2129,15 @@ } ], "parameters": [ + { + "name": "group_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "title": "Group Id" + } + }, { "name": "account_id", "in": "path", @@ -2048,6 +2210,15 @@ } ], "parameters": [ + { + "name": "group_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "title": "Group Id" + } + }, { "name": "account_id", "in": "path", @@ -2469,6 +2640,15 @@ "created_by": { "type": "integer", "title": "Created By" + }, + "last_changed": { + "type": "string", + "format": "date-time", + "title": "Last Changed" + }, + "archived": { + "type": "boolean", + "title": "Archived" } }, "type": "object", @@ -2480,7 +2660,9 @@ "terms", "add_user_account_on_join", "created_at", - "created_by" + "created_by", + "last_changed", + "archived" ], "title": "Group" }, diff --git a/frontend/apps/mobile/src/navigation/DrawerContent.tsx b/frontend/apps/mobile/src/navigation/DrawerContent.tsx index 2627090..fda3565 100644 --- a/frontend/apps/mobile/src/navigation/DrawerContent.tsx +++ b/frontend/apps/mobile/src/navigation/DrawerContent.tsx @@ -15,7 +15,7 @@ export const DrawerContent: React.FC = (props) => { const dispatch = useAppDispatch(); const navigation = useNavigation>(); const activeGroupID = useAppSelector(selectActiveGroupId); - const groups = useAppSelector(selectGroups); + const groups = useAppSelector((state) => selectGroups(state, false)); if (!api) { return null; diff --git a/frontend/apps/mobile/src/navigation/Navigation.tsx b/frontend/apps/mobile/src/navigation/Navigation.tsx index e6c65e9..a49d6d6 100644 --- a/frontend/apps/mobile/src/navigation/Navigation.tsx +++ b/frontend/apps/mobile/src/navigation/Navigation.tsx @@ -43,7 +43,7 @@ const RootNavigator: React.FC = () => { const { api, websocket } = useOptionalApi(); const dispatch = useAppDispatch(); const activeGroupId = useAppSelector(selectActiveGroupId); - const groups = useAppSelector(selectGroups); + const groups = useAppSelector((state) => selectGroups(state, false)); const isAuthenticated = useAppSelector(selectIsAuthenticated); useEffect(() => { diff --git a/frontend/apps/mobile/src/screens/TransactionList/TransactionList.tsx b/frontend/apps/mobile/src/screens/TransactionList/TransactionList.tsx index 4d6a0f6..3cc7075 100644 --- a/frontend/apps/mobile/src/screens/TransactionList/TransactionList.tsx +++ b/frontend/apps/mobile/src/screens/TransactionList/TransactionList.tsx @@ -4,8 +4,8 @@ import { createTransaction, fetchTransactions, selectGroupTransactionsStatus, - useCurrentUserPermissions, useGroup, + useIsGroupWritable, useSortedTransactions, } from "@abrechnung/redux"; import { Transaction, TransactionType } from "@abrechnung/types"; @@ -36,7 +36,7 @@ export const TransactionList: React.FC = ({ navigation }) => { const [sortMode, setSortMode] = useState("last_changed"); const transactions = useSortedTransactions(groupId, sortMode, search); const transactionStatus = useAppSelector((state) => selectGroupTransactionsStatus(state, groupId)); - const permissions = useCurrentUserPermissions(groupId); + const isGroupWritable = useIsGroupWritable(groupId); const [refreshing, setRefreshing] = useState(false); const [isFapOpen, setFabOpen] = useState(false); @@ -144,7 +144,7 @@ export const TransactionList: React.FC = ({ navigation }) => { onRefresh={onRefresh} refreshing={refreshing} ListFooterComponent={ - permissions?.can_write ? ( + isGroupWritable ? ( > = ( .sort((f1, f2) => fromISOString(f2.last_changed).getTime() - fromISOString(f1.last_changed).getTime()); const currency_symbol = useGroupCurrencySymbol(groupId); - const permissions = useCurrentUserPermissions(groupId); + const isGroupWritable = useIsGroupWritable(groupId); const [confirmDeleteModalOpen, setConfirmDeleteModalOpen] = React.useState(false); @@ -80,7 +80,7 @@ export const AccountDetail: React.FC> = ( navigation.setOptions({ headerTitle: account?.name || "", headerRight: () => { - if (permissions === undefined || !permissions.can_write) { + if (!isGroupWritable) { return null; } return ( @@ -91,7 +91,7 @@ export const AccountDetail: React.FC> = ( ); }, }); - }, [accountId, permissions, groupId, theme, account, navigation]); + }, [accountId, isGroupWritable, groupId, theme, account, navigation]); const renderTransactionListEntryTransaction = (transaction: Transaction) => ( > = ({ ro const { groupId, accountId } = route.params; const account = useAccount(groupId, accountId); - const permissions = useCurrentUserPermissions(groupId); + const isGroupWritable = useIsGroupWritable(groupId); const onGoBack = React.useCallback(async () => { if (account) { @@ -68,10 +68,10 @@ export const AccountEdit: React.FC> = ({ ro ); useEffect(() => { - if (permissions === undefined || !permissions.can_write) { + if (!isGroupWritable) { navigation.replace("AccountDetail", { accountId, groupId }); } - }, [navigation, accountId, permissions, groupId]); + }, [navigation, accountId, isGroupWritable, groupId]); const formik = useFormik({ initialValues: diff --git a/frontend/apps/mobile/src/screens/groups/AccountList.tsx b/frontend/apps/mobile/src/screens/groups/AccountList.tsx index 6e5c60a..31dec57 100644 --- a/frontend/apps/mobile/src/screens/groups/AccountList.tsx +++ b/frontend/apps/mobile/src/screens/groups/AccountList.tsx @@ -5,8 +5,8 @@ import { fetchAccounts, selectAccountBalances, selectGroupAccountsStatus, - useCurrentUserPermissions, useGroup, + useIsGroupWritable, useSortedAccounts, } from "@abrechnung/redux"; import { Account, AccountBalance } from "@abrechnung/types"; @@ -39,7 +39,7 @@ export const AccountList: React.FC = ({ route, navigation }) => { const [sortMode, setSortMode] = useState("name"); const accounts = useSortedAccounts(groupId, sortMode, accountType, search); const accountBalances = useAppSelector((state) => selectAccountBalances(state, groupId)); - const permissions = useCurrentUserPermissions(groupId); + const isGroupWritable = useIsGroupWritable(groupId); const currency_symbol = group?.currency_symbol; const accountStatus = useAppSelector((state) => selectGroupAccountsStatus(state, groupId)); @@ -188,7 +188,7 @@ export const AccountList: React.FC = ({ route, navigation }) => { data={accounts} renderItem={renderItem} ListFooterComponent={ - permissions?.can_write ? ( + isGroupWritable ? ( diff --git a/frontend/apps/mobile/src/screens/groups/TransactionDetail.tsx b/frontend/apps/mobile/src/screens/groups/TransactionDetail.tsx index b71b740..f32848a 100644 --- a/frontend/apps/mobile/src/screens/groups/TransactionDetail.tsx +++ b/frontend/apps/mobile/src/screens/groups/TransactionDetail.tsx @@ -3,7 +3,7 @@ import { discardTransactionChange, saveTransaction, selectTransactionHasPositions, - useCurrentUserPermissions, + useIsGroupWritable, useTransaction, useWipTransactionPositions, wipTransactionUpdated, @@ -54,7 +54,7 @@ export const TransactionDetail: React.FC acc + curr.price, 0); - const permissions = useCurrentUserPermissions(groupId); + const isGroupWritable = useIsGroupWritable(groupId); const onGoBack = React.useCallback(async () => { if (editing && transaction != null) { @@ -93,10 +93,10 @@ export const TransactionDetail: React.FC { - if (editing && (permissions === undefined || !permissions.can_write)) { + if (editing && !isGroupWritable) { navigation.replace("TransactionDetail", { transactionId, groupId, editing: false }); } - }, [editing, permissions, transactionId, groupId, navigation]); + }, [editing, isGroupWritable, transactionId, groupId, navigation]); const formik = useFormik({ initialValues: @@ -175,7 +175,7 @@ export const TransactionDetail: React.FC { - if (permissions === undefined || !permissions.can_write) { + if (!isGroupWritable) { return null; } if (editing) { @@ -197,7 +197,18 @@ export const TransactionDetail: React.FC; diff --git a/frontend/apps/web/src/app/authenticated-layout/SidebarGroupList.tsx b/frontend/apps/web/src/app/authenticated-layout/SidebarGroupList.tsx index f81dd5d..b317859 100644 --- a/frontend/apps/web/src/app/authenticated-layout/SidebarGroupList.tsx +++ b/frontend/apps/web/src/app/authenticated-layout/SidebarGroupList.tsx @@ -14,7 +14,7 @@ interface Props { export const SidebarGroupList: React.FC = ({ activeGroupId }) => { const { t } = useTranslation(); const isGuest = useAppSelector(selectIsGuestUser); - const groups = useAppSelector((state) => selectGroups(state)); + const groups = useAppSelector((state) => selectGroups(state, false)); const [showGroupCreationModal, setShowGroupCreationModal] = useState(false); const openGroupCreateModal = () => { @@ -30,9 +30,9 @@ export const SidebarGroupList: React.FC = ({ activeGroupId }) => { return ( <> - + - +
{groups.map((it) => ( = ({ group }) => { + const { t } = useTranslation(); + + if (!group.archived) { + return null; + } + + return {t("groups.archivedDisclaimer")}; +}; diff --git a/frontend/apps/web/src/components/accounts/AccountTransactionList.tsx b/frontend/apps/web/src/components/accounts/AccountTransactionList.tsx index 97439af..c5e1962 100644 --- a/frontend/apps/web/src/components/accounts/AccountTransactionList.tsx +++ b/frontend/apps/web/src/components/accounts/AccountTransactionList.tsx @@ -71,7 +71,7 @@ export const AccountTransactionList: React.FC = ({ groupId, account }) => - {combinedList.length === 0 && None so far.} + {combinedList.length === 0 && {t("common.noneSoFar")}} {combinedList.map((entry) => { if (entry.type === "clearing") { return ( diff --git a/frontend/apps/web/src/components/accounts/BalanceHistoryGraph.tsx b/frontend/apps/web/src/components/accounts/BalanceHistoryGraph.tsx index 6199231..4f5da58 100644 --- a/frontend/apps/web/src/components/accounts/BalanceHistoryGraph.tsx +++ b/frontend/apps/web/src/components/accounts/BalanceHistoryGraph.tsx @@ -8,12 +8,13 @@ import { useGroupCurrencySymbol, } from "@abrechnung/redux"; import { fromISOString, toISODateString } from "@abrechnung/utils"; -import { Card, Divider, Theme, Typography, useTheme } from "@mui/material"; +import { Alert, Card, Divider, Theme, Typography, useTheme } from "@mui/material"; import { PointMouseHandler, PointTooltipProps, ResponsiveLine, Serie } from "@nivo/line"; import { DateTime } from "luxon"; import React from "react"; import { useNavigate } from "react-router-dom"; import { ClearingAccountIcon, PurchaseIcon, TransferIcon } from "../style/AbrechnungIcons"; +import { useTranslation } from "react-i18next"; interface Props { groupId: number; @@ -21,6 +22,7 @@ interface Props { } export const BalanceHistoryGraph: React.FC = ({ groupId, accountId }) => { + const { t } = useTranslation(); const theme: Theme = useTheme(); const navigate = useNavigate(); @@ -141,6 +143,12 @@ export const BalanceHistoryGraph: React.FC = ({ groupId, accountId }) => ); }; + // workaround for errors in nivo when passed empty data arrays. + // Nivo throws an error when having set useMesh=true upon mouse hover for empty data arrays + if (graphData.length === 0) { + return {t("common.noneSoFar")}; + } + return (
= ({ groupId, account }) => { const dispatch = useAppDispatch(); const navigate = useNavigate(); - const permissions = useCurrentUserPermissions(groupId); + const isGroupWritable = useIsGroupWritable(groupId); const currencySymbol = useGroupCurrencySymbol(groupId); const balances = useAppSelector((state) => selectAccountBalances(state, groupId)); @@ -111,7 +111,7 @@ export const AccountInfo: React.FC = ({ groupId, account }) => { navigate(`/groups/${groupId}/${account.type === "clearing" ? "events" : "accounts"}`); }; - if (!permissions || !currencySymbol) { + if (!currencySymbol) { return ; } @@ -125,7 +125,7 @@ export const AccountInfo: React.FC = ({ groupId, account }) => { - {permissions.can_write && ( + {isGroupWritable && ( <> {account.is_wip ? ( <> diff --git a/frontend/apps/web/src/pages/accounts/Balances.tsx b/frontend/apps/web/src/pages/accounts/Balances.tsx index 59d63f6..df2dbd4 100644 --- a/frontend/apps/web/src/pages/accounts/Balances.tsx +++ b/frontend/apps/web/src/pages/accounts/Balances.tsx @@ -3,7 +3,13 @@ import { MobilePaper, ListItemLink } from "@/components/style"; import { useTitle } from "@/core/utils"; import { useFormatCurrency } from "@/hooks"; import { useAppSelector } from "@/store"; -import { selectAccountBalances, useGroup, useGroupAccounts, useSortedAccounts } from "@abrechnung/redux"; +import { + selectAccountBalances, + useGroup, + useGroupAccounts, + useIsGroupWritable, + useSortedAccounts, +} from "@abrechnung/redux"; import { TabContext, TabList, TabPanel } from "@mui/lab"; import { Alert, @@ -23,6 +29,7 @@ import React, { useState } from "react"; import { useTranslation } from "react-i18next"; import { Navigate, Link as RouterLink } from "react-router-dom"; import { BalanceBarGraph } from "./BalanceBarGraph"; +import { GroupArchivedDisclaimer } from "@/components"; interface Props { groupId: number; @@ -38,6 +45,7 @@ export const Balances: React.FC = ({ groupId }) => { const personalAccounts = useSortedAccounts(groupId, "name", "personal"); const clearingAccounts = useGroupAccounts(groupId, "clearing"); const balances = useAppSelector((state) => selectAccountBalances(state, groupId)); + const isGroupWritable = useIsGroupWritable(groupId); const [selectedTab, setSelectedTab] = useState("1"); @@ -62,6 +70,7 @@ export const Balances: React.FC = ({ groupId }) => { return ( + setSelectedTab(idx)} centered> @@ -121,12 +130,16 @@ export const Balances: React.FC = ({ groupId }) => { - - - - + {isGroupWritable && ( + <> + + + + + + )} ); }; diff --git a/frontend/apps/web/src/pages/accounts/ClearingAccountList/ClearingAccountList.tsx b/frontend/apps/web/src/pages/accounts/ClearingAccountList/ClearingAccountList.tsx index 36c134a..285301b 100644 --- a/frontend/apps/web/src/pages/accounts/ClearingAccountList/ClearingAccountList.tsx +++ b/frontend/apps/web/src/pages/accounts/ClearingAccountList/ClearingAccountList.tsx @@ -1,5 +1,5 @@ import { AccountSortMode } from "@abrechnung/core"; -import { createAccount, useCurrentUserPermissions, useGroup, useSortedAccounts } from "@abrechnung/redux"; +import { createAccount, useGroup, useIsGroupWritable, useSortedAccounts } from "@abrechnung/redux"; import { Add as AddIcon, Clear as ClearIcon, Search as SearchIcon } from "@mui/icons-material"; import { Alert, @@ -32,6 +32,7 @@ import { getAccountLink } from "@/utils"; import { ClearingAccountListItem } from "./ClearingAccountListItem"; import { useTranslation } from "react-i18next"; import { Account } from "@abrechnung/types"; +import { GroupArchivedDisclaimer } from "@/components"; interface Props { groupId: number; @@ -45,13 +46,13 @@ export const ClearingAccountList: React.FC = ({ groupId }) => { const dispatch = useAppDispatch(); const navigate = useNavigate(); const group = useGroup(groupId); + const isGroupWritable = useIsGroupWritable(groupId); const theme: Theme = useTheme(); const isSmallScreen = useMediaQuery(theme.breakpoints.down("md")); const [searchValue, setSearchValue] = useState(""); const [tagFilter, setTagFilter] = useState(emptyList); const [sortMode, setSortMode] = useState("last_changed"); - const permissions = useCurrentUserPermissions(groupId); const clearingAccounts = useSortedAccounts(groupId, sortMode, "clearing", searchValue, true, tagFilter); const [currentPage, setCurrentPage] = useState(0); @@ -82,7 +83,7 @@ export const ClearingAccountList: React.FC = ({ groupId }) => { }); }; - if (!permissions) { + if (!group) { return ; } @@ -90,6 +91,7 @@ export const ClearingAccountList: React.FC = ({ groupId }) => { <> + = ({ groupId }) => { /> - {!isSmallScreen && ( + {!isSmallScreen && isGroupWritable && ( @@ -168,7 +170,7 @@ export const ClearingAccountList: React.FC = ({ groupId }) => { paginatedAccounts.map((account) => ( @@ -189,7 +191,7 @@ export const ClearingAccountList: React.FC = ({ groupId }) => { )} - {permissions.can_write && ( + {isGroupWritable && ( <> void; } -export const ClearingAccountListItem: React.FC = ({ groupId, account, setAccountToDelete }) => { +export const ClearingAccountListItem: React.FC = ({ group, account, setAccountToDelete }) => { const dispatch = useAppDispatch(); const navigate = useNavigate(); - const permissions = useCurrentUserPermissions(groupId); - const accounts = useAppSelector((state) => selectAccountIdToAccountMap(state, groupId)); + const isGroupWritable = useIsGroupWritable(group.id); + const accounts = useAppSelector((state) => selectAccountIdToAccountMap(state, group.id)); - if (!permissions || account.type !== "clearing") { + if (account.type !== "clearing") { return null; } @@ -35,18 +31,18 @@ export const ClearingAccountListItem: React.FC = ({ groupId, account, set const edit = () => { if (!account.is_wip) { - dispatch(accountEditStarted({ groupId, accountId: account.id })); + dispatch(accountEditStarted({ groupId: group.id, accountId: account.id })); } - navigate(getAccountLink(groupId, account.type, account.id)); + navigate(getAccountLink(group.id, account.type, account.id)); }; const copy = () => { - dispatch(copyAccount({ groupId, accountId: account.id })); + dispatch(copyAccount({ groupId: group.id, accountId: account.id })); }; return ( - + = ({ groupId, account, set } /> - {permissions.can_write && ( + {isGroupWritable && ( diff --git a/frontend/apps/web/src/pages/accounts/PersonalAccountList/PersonalAccountList.tsx b/frontend/apps/web/src/pages/accounts/PersonalAccountList/PersonalAccountList.tsx index 06b7155..59ab26a 100644 --- a/frontend/apps/web/src/pages/accounts/PersonalAccountList/PersonalAccountList.tsx +++ b/frontend/apps/web/src/pages/accounts/PersonalAccountList/PersonalAccountList.tsx @@ -3,13 +3,7 @@ import { MobilePaper } from "@/components/style"; import { useTitle } from "@/core/utils"; import { useAppDispatch, useAppSelector } from "@/store"; import { AccountSortMode } from "@abrechnung/core"; -import { - createAccount, - selectCurrentUserId, - useCurrentUserPermissions, - useGroup, - useSortedAccounts, -} from "@abrechnung/redux"; +import { createAccount, selectCurrentUserId, useGroup, useIsGroupWritable, useSortedAccounts } from "@abrechnung/redux"; import { Add as AddIcon, Clear as ClearIcon, Search as SearchIcon } from "@mui/icons-material"; import { Alert, @@ -37,6 +31,7 @@ import { toast } from "react-toastify"; import { PersonalAccountListItem } from "./PersonalAccountListItem"; import { useTranslation } from "react-i18next"; import { Account } from "@abrechnung/types"; +import { GroupArchivedDisclaimer } from "@/components"; interface Props { groupId: number; @@ -57,7 +52,7 @@ export const PersonalAccountList: React.FC = ({ groupId }) => { const personalAccounts = useSortedAccounts(groupId, sortMode, "personal", searchValue); - const permissions = useCurrentUserPermissions(groupId); + const isGroupWritable = useIsGroupWritable(groupId); const currentUserId = useAppSelector(selectCurrentUserId); const [currentPage, setCurrentPage] = useState(0); @@ -89,7 +84,7 @@ export const PersonalAccountList: React.FC = ({ groupId }) => { }); }; - if (!group || !permissions || currentUserId == null) { + if (!group || currentUserId == null) { return ; } @@ -97,6 +92,7 @@ export const PersonalAccountList: React.FC = ({ groupId }) => { <> + = ({ groupId }) => { - {!isSmallScreen && ( + {!isSmallScreen && isGroupWritable && ( @@ -185,7 +181,7 @@ export const PersonalAccountList: React.FC = ({ groupId }) => { )} - {permissions.can_write && ( + {isGroupWritable && ( <> = ({ groupId, currentUserI const dispatch = useAppDispatch(); const navigate = useNavigate(); - const permissions = useCurrentUserPermissions(groupId); + const isGroupWritable = useIsGroupWritable(groupId); - if (!permissions || !account) { + if (!account) { return ; } @@ -58,7 +58,7 @@ export const PersonalAccountListItem: React.FC = ({ groupId, currentUserI secondary={account.description} /> - {permissions.can_write && ( + {isGroupWritable && ( diff --git a/frontend/apps/web/src/pages/groups/GroupList.tsx b/frontend/apps/web/src/pages/groups/GroupList.tsx index 7aae026..e09be30 100644 --- a/frontend/apps/web/src/pages/groups/GroupList.tsx +++ b/frontend/apps/web/src/pages/groups/GroupList.tsx @@ -9,6 +9,7 @@ import { ListItem, ListItemSecondaryAction, ListItemText, + Stack, Typography, } from "@mui/material"; import { Add, Delete } from "@mui/icons-material"; @@ -18,14 +19,11 @@ import { useAppSelector } from "@/store"; import { useTitle } from "@/core/utils"; import { useTranslation } from "react-i18next"; import { Group } from "@abrechnung/api"; +import { DateTime } from "luxon"; -export const GroupList: React.FC = () => { +const GList: React.FC<{ groups: Group[] }> = ({ groups }) => { const { t } = useTranslation(); - useTitle(t("groups.list.tabTitle")); - const [showGroupCreationModal, setShowGroupCreationModal] = useState(false); const [groupToDelete, setGroupToDelete] = useState(null); - const groups = useAppSelector((state) => selectGroups(state)); - const isGuest = useAppSelector(selectIsGuestUser); const openGroupDeletionModal = (groupID: number) => { const g = groups.find((group) => group.id === groupID); @@ -38,22 +36,8 @@ export const GroupList: React.FC = () => { setGroupToDelete(null); }; - const openGroupCreateModal = () => { - setShowGroupCreationModal(true); - }; - - const closeGroupCreateModal = (reason: string) => { - if (reason !== "backdropClick") { - setShowGroupCreationModal(false); - } - }; - return ( - - - {t("groups.list.header")} - - {isGuest && {t("groups.list.guestUserDisclaimer")}} + <> {groups.length === 0 ? ( @@ -62,10 +46,25 @@ export const GroupList: React.FC = () => { ) : ( groups.map((group) => { return ( - - - - + + + {group.description && ( + <> + {group.description} +
+ + )} + {t("common.lastChangedWithTime", { + datetime: DateTime.fromISO(group.last_changed).toLocaleString( + DateTime.DATETIME_FULL + ), + })} + + } + /> { -
+ ); }) )}
- {!isGuest && ( - <> - - - - - - - - )} {groupToDelete != null && ( { groupToDelete={groupToDelete} /> )} -
+ + ); +}; + +export const GroupList: React.FC = () => { + const { t } = useTranslation(); + useTitle(t("groups.list.tabTitle")); + const [showGroupCreationModal, setShowGroupCreationModal] = useState(false); + const groups = useAppSelector((state) => selectGroups(state, false)); + const archivedGroups = useAppSelector((state) => selectGroups(state, true)); + const isGuest = useAppSelector(selectIsGuestUser); + + const openGroupCreateModal = () => { + setShowGroupCreationModal(true); + }; + + const closeGroupCreateModal = (reason: string) => { + if (reason !== "backdropClick") { + setShowGroupCreationModal(false); + } + }; + + return ( + + + + {t("groups.list.header")} + + {isGuest && {t("groups.list.guestUserDisclaimer")}} + + {!isGuest && ( + <> + + + + + + + + )} + + {archivedGroups.length > 0 && ( + + + {t("groups.list.archivedGroups")} + + + + )} + ); }; diff --git a/frontend/apps/web/src/pages/groups/settings/GroupSettingsPage.tsx b/frontend/apps/web/src/pages/groups/settings/GroupSettingsPage.tsx index 3e01e6a..9fd53fc 100644 --- a/frontend/apps/web/src/pages/groups/settings/GroupSettingsPage.tsx +++ b/frontend/apps/web/src/pages/groups/settings/GroupSettingsPage.tsx @@ -1,20 +1,158 @@ import { MobilePaper } from "@/components/style"; import { useTitle } from "@/core/utils"; -import { useCurrentUserPermissions, useGroup } from "@abrechnung/redux"; -import { Alert, Box, Stack, Tab } from "@mui/material"; +import { Group, GroupMember } from "@abrechnung/api"; +import { archiveGroup, leaveGroup, unarchiveGroup, useCurrentUserPermissions, useGroup } from "@abrechnung/redux"; +import { useQueryVar } from "@abrechnung/utils"; +import { TabContext, TabList, TabPanel } from "@mui/lab"; +import { + Alert, + Box, + Button, + Dialog, + DialogActions, + DialogContent, + DialogContentText, + DialogTitle, + Stack, + Tab, +} from "@mui/material"; import * as React from "react"; import { useTranslation } from "react-i18next"; -import { Navigate } from "react-router-dom"; -import { SettingsForm } from "./SettingsForm"; -import { GroupMemberList } from "./GroupMemberList"; -import { TabContext, TabList, TabPanel } from "@mui/lab"; -import { useQueryVar } from "@abrechnung/utils"; +import { Navigate, useNavigate } from "react-router-dom"; import { GroupInvites } from "./GroupInvites"; +import { GroupMemberList } from "./GroupMemberList"; +import { SettingsForm } from "./SettingsForm"; +import { useAppDispatch } from "@/store"; +import { api } from "@/core/api"; +import { toast } from "react-toastify"; +import { Archive as ArchiveIcon, Logout as LogoutIcon } from "@mui/icons-material"; +import { GroupArchivedDisclaimer } from "@/components"; interface Props { groupId: number; } +const GroupActions: React.FC<{ group: Group; permissions: GroupMember }> = ({ group, permissions }) => { + const { t } = useTranslation(); + const [showLeaveModal, setShowLeaveModal] = React.useState(false); + const [showArchiveModal, setShowArchiveModal] = React.useState(false); + const [showUnarchiveModal, setShowUnarchiveModal] = React.useState(false); + const dispatch = useAppDispatch(); + const navigate = useNavigate(); + + const confirmLeaveGroup = () => { + dispatch(leaveGroup({ groupId: group.id, api })) + .unwrap() + .then(() => { + navigate("/"); + }) + .catch((err) => { + toast.error(err); + }); + }; + + const confirmArchiveGroup = () => { + dispatch(archiveGroup({ groupId: group.id, api })) + .unwrap() + .then(() => setShowArchiveModal(false)) + .catch((err) => { + toast.error(err.message); + }); + }; + + const confirmUnarchiveGroup = () => { + dispatch(unarchiveGroup({ groupId: group.id, api })) + .unwrap() + .then(() => setShowUnarchiveModal(false)) + .catch((err) => { + toast.error(err.message); + }); + }; + + return ( + <> + + + {permissions.is_owner && !group.archived && ( + + )} + {permissions.is_owner && group.archived && ( + + )} + + setShowLeaveModal(false)}> + {t("groups.settings.leaveGroup")} + + + {t("groups.settings.leaveGroupConfirm", { group })} + + + + + + + + setShowArchiveModal(false)}> + {t("groups.settings.archiveGroup")} + + + {t("groups.settings.archiveGroupConfirm", { group })} + + + + + + + + setShowUnarchiveModal(false)}> + {t("groups.settings.unarchiveGroup")} + + + {t("groups.settings.unarchiveGroupConfirm", { group })} + + + + + + + + + ); +}; + export const GroupSettingsPage: React.FC = ({ groupId }) => { const { t } = useTranslation(); const [activeTab, setActiveTab] = useQueryVar("activeTab", "settings"); @@ -39,12 +177,18 @@ export const GroupSettingsPage: React.FC = ({ groupId }) => { - {permissions.is_owner ? ( - {t("groups.settings.ownerDisclaimer")} - ) : !permissions.can_write ? ( - {t("groups.settings.readAccessDisclaimer")} - ) : null} + + + {permissions.is_owner ? ( + {t("groups.settings.ownerDisclaimer")} + ) : !permissions.can_write ? ( + {t("groups.settings.readAccessDisclaimer")} + ) : null} + + + + diff --git a/frontend/apps/web/src/pages/transactions/TransactionDetail/TransactionActions.tsx b/frontend/apps/web/src/pages/transactions/TransactionDetail/TransactionActions.tsx index cbda866..a52bd78 100644 --- a/frontend/apps/web/src/pages/transactions/TransactionDetail/TransactionActions.tsx +++ b/frontend/apps/web/src/pages/transactions/TransactionDetail/TransactionActions.tsx @@ -14,7 +14,7 @@ import React, { useState } from "react"; import { Navigate, useNavigate } from "react-router-dom"; import { useTranslation } from "react-i18next"; import { Transaction } from "@abrechnung/types"; -import { useCurrentUserPermissions } from "@abrechnung/redux"; +import { useGroup, useIsGroupWritable } from "@abrechnung/redux"; interface Props { groupId: number; @@ -39,9 +39,10 @@ export const TransactionActions: React.FC = ({ const navigate = useNavigate(); const [confirmDeleteDialogOpen, setConfirmDeleteDialogOpen] = useState(false); - const permissions = useCurrentUserPermissions(groupId); + const isGroupWritable = useIsGroupWritable(groupId); + const group = useGroup(groupId); - if (!permissions) { + if (!group) { return ; } @@ -61,7 +62,7 @@ export const TransactionActions: React.FC = ({
- {permissions.can_write && ( + {isGroupWritable && ( <> {transaction.is_wip ? ( <> diff --git a/frontend/apps/web/src/pages/transactions/TransactionList/TransactionList.tsx b/frontend/apps/web/src/pages/transactions/TransactionList/TransactionList.tsx index 6fa77eb..f058b5e 100644 --- a/frontend/apps/web/src/pages/transactions/TransactionList/TransactionList.tsx +++ b/frontend/apps/web/src/pages/transactions/TransactionList/TransactionList.tsx @@ -2,9 +2,9 @@ import { TransactionSortMode, transactionCsvDump } from "@abrechnung/core"; import { createTransaction, selectTransactionBalanceEffects, - useCurrentUserPermissions, useGroup, useGroupAccounts, + useIsGroupWritable, useSortedTransactions, } from "@abrechnung/redux"; import { Add, Clear } from "@mui/icons-material"; @@ -42,6 +42,7 @@ import { useAppDispatch, useAppSelector } from "@/store"; import { TransactionListItem } from "./TransactionListItem"; import { useTranslation } from "react-i18next"; import { Transaction } from "@abrechnung/types"; +import { GroupArchivedDisclaimer } from "@/components"; interface Props { groupId: number; @@ -84,7 +85,7 @@ export const TransactionList: React.FC = ({ groupId }) => { const [speedDialOpen, setSpeedDialOpen] = useState(false); const toggleSpeedDial = () => setSpeedDialOpen((currValue) => !currValue); - const permissions = useCurrentUserPermissions(groupId); + const isGroupWritable = useIsGroupWritable(groupId); const [searchValue, setSearchValue] = useState(""); const [tagFilter, setTagFilter] = useState(emptyList); @@ -123,7 +124,7 @@ export const TransactionList: React.FC = ({ groupId }) => { const downloadCsv = useDownloadCsv(groupId, transactions); - if (!permissions) { + if (!group) { return ; } @@ -131,6 +132,7 @@ export const TransactionList: React.FC = ({ groupId }) => { <> + = ({ groupId }) => { /> - {!isSmallScreen && permissions.can_write && ( + {!isSmallScreen && ( - {permissions.can_write && ( + {isGroupWritable && ( <>
@@ -246,7 +248,7 @@ export const TransactionList: React.FC = ({ groupId }) => { )} - {permissions.can_write && ( + {isGroupWritable && ( = ({ groupId, transactionId, s // get the new group id with the old transaction id => the transaction will be undefined as it does not exist in the new group // // a possible solution would be to track the currently active group in the redux store as well and not pass it to the selectors - // and components, unsure if this would work properly though. Additionally it leaves us with less flexibility when reuxing + // and components, unsure if this would work properly though. Additionally it leaves us with less flexibility when reusing // selectors as they will always work on the currently active group. return null; } diff --git a/frontend/libs/api/src/lib/generated/Client.ts b/frontend/libs/api/src/lib/generated/Client.ts index d9d5fd8..90ce597 100644 --- a/frontend/libs/api/src/lib/generated/Client.ts +++ b/frontend/libs/api/src/lib/generated/Client.ts @@ -1,41 +1,35 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { BaseHttpRequest } from "./core/BaseHttpRequest"; -import type { OpenAPIConfig } from "./core/OpenAPI"; -import { FetchHttpRequest } from "./core/FetchHttpRequest"; - -import { AccountsService } from "./services/AccountsService"; -import { AuthService } from "./services/AuthService"; -import { CommonService } from "./services/CommonService"; -import { GroupsService } from "./services/GroupsService"; -import { TransactionsService } from "./services/TransactionsService"; - +import type { BaseHttpRequest } from './core/BaseHttpRequest'; +import type { OpenAPIConfig } from './core/OpenAPI'; +import { FetchHttpRequest } from './core/FetchHttpRequest'; +import { AccountsService } from './services/AccountsService'; +import { AuthService } from './services/AuthService'; +import { CommonService } from './services/CommonService'; +import { GroupsService } from './services/GroupsService'; +import { TransactionsService } from './services/TransactionsService'; type HttpRequestConstructor = new (config: OpenAPIConfig) => BaseHttpRequest; - export class Client { public readonly accounts: AccountsService; public readonly auth: AuthService; public readonly common: CommonService; public readonly groups: GroupsService; public readonly transactions: TransactionsService; - public readonly request: BaseHttpRequest; - constructor(config?: Partial, HttpRequest: HttpRequestConstructor = FetchHttpRequest) { this.request = new HttpRequest({ - BASE: config?.BASE ?? "", - VERSION: config?.VERSION ?? "0.10.1", + BASE: config?.BASE ?? '', + VERSION: config?.VERSION ?? '0.14.0', WITH_CREDENTIALS: config?.WITH_CREDENTIALS ?? false, - CREDENTIALS: config?.CREDENTIALS ?? "include", + CREDENTIALS: config?.CREDENTIALS ?? 'include', TOKEN: config?.TOKEN, USERNAME: config?.USERNAME, PASSWORD: config?.PASSWORD, HEADERS: config?.HEADERS, ENCODE_PATH: config?.ENCODE_PATH, }); - this.accounts = new AccountsService(this.request); this.auth = new AuthService(this.request); this.common = new CommonService(this.request); @@ -43,3 +37,4 @@ export class Client { this.transactions = new TransactionsService(this.request); } } + diff --git a/frontend/libs/api/src/lib/generated/core/ApiError.ts b/frontend/libs/api/src/lib/generated/core/ApiError.ts index 822a514..ec7b16a 100644 --- a/frontend/libs/api/src/lib/generated/core/ApiError.ts +++ b/frontend/libs/api/src/lib/generated/core/ApiError.ts @@ -1,9 +1,9 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { ApiRequestOptions } from "./ApiRequestOptions"; -import type { ApiResult } from "./ApiResult"; +import type { ApiRequestOptions } from './ApiRequestOptions'; +import type { ApiResult } from './ApiResult'; export class ApiError extends Error { public readonly url: string; @@ -15,7 +15,7 @@ export class ApiError extends Error { constructor(request: ApiRequestOptions, response: ApiResult, message: string) { super(message); - this.name = "ApiError"; + this.name = 'ApiError'; this.url = response.url; this.status = response.status; this.statusText = response.statusText; diff --git a/frontend/libs/api/src/lib/generated/core/ApiRequestOptions.ts b/frontend/libs/api/src/lib/generated/core/ApiRequestOptions.ts index 00ee4a5..93143c3 100644 --- a/frontend/libs/api/src/lib/generated/core/ApiRequestOptions.ts +++ b/frontend/libs/api/src/lib/generated/core/ApiRequestOptions.ts @@ -1,9 +1,9 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ export type ApiRequestOptions = { - readonly method: "GET" | "PUT" | "POST" | "DELETE" | "OPTIONS" | "HEAD" | "PATCH"; + readonly method: 'GET' | 'PUT' | 'POST' | 'DELETE' | 'OPTIONS' | 'HEAD' | 'PATCH'; readonly url: string; readonly path?: Record; readonly cookies?: Record; diff --git a/frontend/libs/api/src/lib/generated/core/ApiResult.ts b/frontend/libs/api/src/lib/generated/core/ApiResult.ts index ad8fef2..ee1126e 100644 --- a/frontend/libs/api/src/lib/generated/core/ApiResult.ts +++ b/frontend/libs/api/src/lib/generated/core/ApiResult.ts @@ -1,4 +1,4 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ diff --git a/frontend/libs/api/src/lib/generated/core/BaseHttpRequest.ts b/frontend/libs/api/src/lib/generated/core/BaseHttpRequest.ts index 5abe596..04aad6a 100644 --- a/frontend/libs/api/src/lib/generated/core/BaseHttpRequest.ts +++ b/frontend/libs/api/src/lib/generated/core/BaseHttpRequest.ts @@ -1,12 +1,13 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { ApiRequestOptions } from "./ApiRequestOptions"; -import type { CancelablePromise } from "./CancelablePromise"; -import type { OpenAPIConfig } from "./OpenAPI"; +import type { ApiRequestOptions } from './ApiRequestOptions'; +import type { CancelablePromise } from './CancelablePromise'; +import type { OpenAPIConfig } from './OpenAPI'; export abstract class BaseHttpRequest { + constructor(public readonly config: OpenAPIConfig) {} public abstract request(options: ApiRequestOptions): CancelablePromise; diff --git a/frontend/libs/api/src/lib/generated/core/CancelablePromise.ts b/frontend/libs/api/src/lib/generated/core/CancelablePromise.ts index ef4e57a..d70de92 100644 --- a/frontend/libs/api/src/lib/generated/core/CancelablePromise.ts +++ b/frontend/libs/api/src/lib/generated/core/CancelablePromise.ts @@ -1,11 +1,12 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ export class CancelError extends Error { + constructor(message: string) { super(message); - this.name = "CancelError"; + this.name = 'CancelError'; } public get isCancelled(): boolean { @@ -50,7 +51,7 @@ export class CancelablePromise implements Promise { return; } this.#isResolved = true; - this.#resolve?.(value); + if (this.#resolve) this.#resolve(value); }; const onReject = (reason?: any): void => { @@ -58,7 +59,7 @@ export class CancelablePromise implements Promise { return; } this.#isRejected = true; - this.#reject?.(reason); + if (this.#reject) this.#reject(reason); }; const onCancel = (cancelHandler: () => void): void => { @@ -68,15 +69,15 @@ export class CancelablePromise implements Promise { this.#cancelHandlers.push(cancelHandler); }; - Object.defineProperty(onCancel, "isResolved", { + Object.defineProperty(onCancel, 'isResolved', { get: (): boolean => this.#isResolved, }); - Object.defineProperty(onCancel, "isRejected", { + Object.defineProperty(onCancel, 'isRejected', { get: (): boolean => this.#isRejected, }); - Object.defineProperty(onCancel, "isCancelled", { + Object.defineProperty(onCancel, 'isCancelled', { get: (): boolean => this.#isCancelled, }); @@ -116,12 +117,12 @@ export class CancelablePromise implements Promise { cancelHandler(); } } catch (error) { - console.warn("Cancellation threw an error", error); + console.warn('Cancellation threw an error', error); return; } } this.#cancelHandlers.length = 0; - this.#reject?.(new CancelError("Request aborted")); + if (this.#reject) this.#reject(new CancelError('Request aborted')); } public get isCancelled(): boolean { diff --git a/frontend/libs/api/src/lib/generated/core/FetchHttpRequest.ts b/frontend/libs/api/src/lib/generated/core/FetchHttpRequest.ts index 7bf2448..e58111a 100644 --- a/frontend/libs/api/src/lib/generated/core/FetchHttpRequest.ts +++ b/frontend/libs/api/src/lib/generated/core/FetchHttpRequest.ts @@ -1,14 +1,15 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { ApiRequestOptions } from "./ApiRequestOptions"; -import { BaseHttpRequest } from "./BaseHttpRequest"; -import type { CancelablePromise } from "./CancelablePromise"; -import type { OpenAPIConfig } from "./OpenAPI"; -import { request as __request } from "./request"; +import type { ApiRequestOptions } from './ApiRequestOptions'; +import { BaseHttpRequest } from './BaseHttpRequest'; +import type { CancelablePromise } from './CancelablePromise'; +import type { OpenAPIConfig } from './OpenAPI'; +import { request as __request } from './request'; export class FetchHttpRequest extends BaseHttpRequest { + constructor(config: OpenAPIConfig) { super(config); } diff --git a/frontend/libs/api/src/lib/generated/core/OpenAPI.ts b/frontend/libs/api/src/lib/generated/core/OpenAPI.ts index b9d8a4f..76e30d8 100644 --- a/frontend/libs/api/src/lib/generated/core/OpenAPI.ts +++ b/frontend/libs/api/src/lib/generated/core/OpenAPI.ts @@ -1,8 +1,8 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { ApiRequestOptions } from "./ApiRequestOptions"; +import type { ApiRequestOptions } from './ApiRequestOptions'; type Resolver = (options: ApiRequestOptions) => Promise; type Headers = Record; @@ -11,7 +11,7 @@ export type OpenAPIConfig = { BASE: string; VERSION: string; WITH_CREDENTIALS: boolean; - CREDENTIALS: "include" | "omit" | "same-origin"; + CREDENTIALS: 'include' | 'omit' | 'same-origin'; TOKEN?: string | Resolver | undefined; USERNAME?: string | Resolver | undefined; PASSWORD?: string | Resolver | undefined; @@ -20,10 +20,10 @@ export type OpenAPIConfig = { }; export const OpenAPI: OpenAPIConfig = { - BASE: "", - VERSION: "0.10.1", + BASE: '', + VERSION: '0.14.0', WITH_CREDENTIALS: false, - CREDENTIALS: "include", + CREDENTIALS: 'include', TOKEN: undefined, USERNAME: undefined, PASSWORD: undefined, diff --git a/frontend/libs/api/src/lib/generated/core/request.ts b/frontend/libs/api/src/lib/generated/core/request.ts index b0bb145..f83d711 100644 --- a/frontend/libs/api/src/lib/generated/core/request.ts +++ b/frontend/libs/api/src/lib/generated/core/request.ts @@ -1,34 +1,34 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import { ApiError } from "./ApiError"; -import type { ApiRequestOptions } from "./ApiRequestOptions"; -import type { ApiResult } from "./ApiResult"; -import { CancelablePromise } from "./CancelablePromise"; -import type { OnCancel } from "./CancelablePromise"; -import type { OpenAPIConfig } from "./OpenAPI"; +import { ApiError } from './ApiError'; +import type { ApiRequestOptions } from './ApiRequestOptions'; +import type { ApiResult } from './ApiResult'; +import { CancelablePromise } from './CancelablePromise'; +import type { OnCancel } from './CancelablePromise'; +import type { OpenAPIConfig } from './OpenAPI'; export const isDefined = (value: T | null | undefined): value is Exclude => { return value !== undefined && value !== null; }; export const isString = (value: any): value is string => { - return typeof value === "string"; + return typeof value === 'string'; }; export const isStringWithValue = (value: any): value is string => { - return isString(value) && value !== ""; + return isString(value) && value !== ''; }; export const isBlob = (value: any): value is Blob => { return ( - typeof value === "object" && - typeof value.type === "string" && - typeof value.stream === "function" && - typeof value.arrayBuffer === "function" && - typeof value.constructor === "function" && - typeof value.constructor.name === "string" && + typeof value === 'object' && + typeof value.type === 'string' && + typeof value.stream === 'function' && + typeof value.arrayBuffer === 'function' && + typeof value.constructor === 'function' && + typeof value.constructor.name === 'string' && /^(Blob|File)$/.test(value.constructor.name) && /^(Blob|File)$/.test(value[Symbol.toStringTag]) ); @@ -43,7 +43,7 @@ export const base64 = (str: string): string => { return btoa(str); } catch (err) { // @ts-ignore - return Buffer.from(str).toString("base64"); + return Buffer.from(str).toString('base64'); } }; @@ -57,10 +57,10 @@ export const getQueryString = (params: Record): string => { const process = (key: string, value: any) => { if (isDefined(value)) { if (Array.isArray(value)) { - value.forEach((v) => { + value.forEach(v => { process(key, v); }); - } else if (typeof value === "object") { + } else if (typeof value === 'object') { Object.entries(value).forEach(([k, v]) => { process(`${key}[${k}]`, v); }); @@ -75,17 +75,17 @@ export const getQueryString = (params: Record): string => { }); if (qs.length > 0) { - return `?${qs.join("&")}`; + return `?${qs.join('&')}`; } - return ""; + return ''; }; const getUrl = (config: OpenAPIConfig, options: ApiRequestOptions): string => { const encoder = config.ENCODE_PATH || encodeURI; const path = options.url - .replace("{api-version}", config.VERSION) + .replace('{api-version}', config.VERSION) .replace(/{(.*?)}/g, (substring: string, group: string) => { if (options.path?.hasOwnProperty(group)) { return encoder(String(options.path[group])); @@ -116,7 +116,7 @@ export const getFormData = (options: ApiRequestOptions): FormData | undefined => .filter(([_, value]) => isDefined(value)) .forEach(([key, value]) => { if (Array.isArray(value)) { - value.forEach((v) => process(key, v)); + value.forEach(v => process(key, v)); } else { process(key, value); } @@ -130,50 +130,49 @@ export const getFormData = (options: ApiRequestOptions): FormData | undefined => type Resolver = (options: ApiRequestOptions) => Promise; export const resolve = async (options: ApiRequestOptions, resolver?: T | Resolver): Promise => { - if (typeof resolver === "function") { + if (typeof resolver === 'function') { return (resolver as Resolver)(options); } return resolver; }; export const getHeaders = async (config: OpenAPIConfig, options: ApiRequestOptions): Promise => { - const token = await resolve(options, config.TOKEN); - const username = await resolve(options, config.USERNAME); - const password = await resolve(options, config.PASSWORD); - const additionalHeaders = await resolve(options, config.HEADERS); + const [token, username, password, additionalHeaders] = await Promise.all([ + resolve(options, config.TOKEN), + resolve(options, config.USERNAME), + resolve(options, config.PASSWORD), + resolve(options, config.HEADERS), + ]); const headers = Object.entries({ - Accept: "application/json", + Accept: 'application/json', ...additionalHeaders, ...options.headers, }) .filter(([_, value]) => isDefined(value)) - .reduce( - (headers, [key, value]) => ({ - ...headers, - [key]: String(value), - }), - {} as Record - ); + .reduce((headers, [key, value]) => ({ + ...headers, + [key]: String(value), + }), {} as Record); if (isStringWithValue(token)) { - headers["Authorization"] = `Bearer ${token}`; + headers['Authorization'] = `Bearer ${token}`; } if (isStringWithValue(username) && isStringWithValue(password)) { const credentials = base64(`${username}:${password}`); - headers["Authorization"] = `Basic ${credentials}`; + headers['Authorization'] = `Basic ${credentials}`; } - if (options.body) { + if (options.body !== undefined) { if (options.mediaType) { - headers["Content-Type"] = options.mediaType; + headers['Content-Type'] = options.mediaType; } else if (isBlob(options.body)) { - headers["Content-Type"] = options.body.type || "application/octet-stream"; + headers['Content-Type'] = options.body.type || 'application/octet-stream'; } else if (isString(options.body)) { - headers["Content-Type"] = "text/plain"; + headers['Content-Type'] = 'text/plain'; } else if (!isFormData(options.body)) { - headers["Content-Type"] = "application/json"; + headers['Content-Type'] = 'application/json'; } } @@ -182,8 +181,8 @@ export const getHeaders = async (config: OpenAPIConfig, options: ApiRequestOptio export const getRequestBody = (options: ApiRequestOptions): any => { if (options.body !== undefined) { - if (options.mediaType?.includes("/json")) { - return JSON.stringify(options.body); + if (options.mediaType?.includes('/json')) { + return JSON.stringify(options.body) } else if (isString(options.body) || isBlob(options.body) || isFormData(options.body)) { return options.body; } else { @@ -233,10 +232,10 @@ export const getResponseHeader = (response: Response, responseHeader?: string): export const getResponseBody = async (response: Response): Promise => { if (response.status !== 204) { try { - const contentType = response.headers.get("Content-Type"); + const contentType = response.headers.get('Content-Type'); if (contentType) { - const jsonTypes = ["application/json", "application/problem+json"]; - const isJSON = jsonTypes.some((type) => contentType.toLowerCase().startsWith(type)); + const jsonTypes = ['application/json', 'application/problem+json'] + const isJSON = jsonTypes.some(type => contentType.toLowerCase().startsWith(type)); if (isJSON) { return await response.json(); } else { @@ -252,15 +251,15 @@ export const getResponseBody = async (response: Response): Promise => { export const catchErrorCodes = (options: ApiRequestOptions, result: ApiResult): void => { const errors: Record = { - 400: "Bad Request", - 401: "Unauthorized", - 403: "Forbidden", - 404: "Not Found", - 500: "Internal Server Error", - 502: "Bad Gateway", - 503: "Service Unavailable", + 400: 'Bad Request', + 401: 'Unauthorized', + 403: 'Forbidden', + 404: 'Not Found', + 500: 'Internal Server Error', + 502: 'Bad Gateway', + 503: 'Service Unavailable', ...options.errors, - }; + } const error = errors[result.status]; if (error) { @@ -268,8 +267,8 @@ export const catchErrorCodes = (options: ApiRequestOptions, result: ApiResult): } if (!result.ok) { - const errorStatus = result.status ?? "unknown"; - const errorStatusText = result.statusText ?? "unknown"; + const errorStatus = result.status ?? 'unknown'; + const errorStatusText = result.statusText ?? 'unknown'; const errorBody = (() => { try { return JSON.stringify(result.body, null, 2); @@ -278,9 +277,7 @@ export const catchErrorCodes = (options: ApiRequestOptions, result: ApiResult): } })(); - throw new ApiError( - options, - result, + throw new ApiError(options, result, `Generic Error: status: ${errorStatus}; status text: ${errorStatusText}; body: ${errorBody}` ); } diff --git a/frontend/libs/api/src/lib/generated/index.ts b/frontend/libs/api/src/lib/generated/index.ts index 1c3ab8f..1f94b39 100644 --- a/frontend/libs/api/src/lib/generated/index.ts +++ b/frontend/libs/api/src/lib/generated/index.ts @@ -1,60 +1,60 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -export { Client } from "./Client"; +export { Client } from './Client'; -export { ApiError } from "./core/ApiError"; -export { BaseHttpRequest } from "./core/BaseHttpRequest"; -export { CancelablePromise, CancelError } from "./core/CancelablePromise"; -export { OpenAPI } from "./core/OpenAPI"; -export type { OpenAPIConfig } from "./core/OpenAPI"; +export { ApiError } from './core/ApiError'; +export { BaseHttpRequest } from './core/BaseHttpRequest'; +export { CancelablePromise, CancelError } from './core/CancelablePromise'; +export { OpenAPI } from './core/OpenAPI'; +export type { OpenAPIConfig } from './core/OpenAPI'; -export type { AccountType } from "./models/AccountType"; -export type { Body_get_token } from "./models/Body_get_token"; -export type { ChangeEmailPayload } from "./models/ChangeEmailPayload"; -export type { ChangePasswordPayload } from "./models/ChangePasswordPayload"; -export type { ClearingAccount } from "./models/ClearingAccount"; -export type { ConfirmEmailChangePayload } from "./models/ConfirmEmailChangePayload"; -export type { ConfirmPasswordRecoveryPayload } from "./models/ConfirmPasswordRecoveryPayload"; -export type { ConfirmRegistrationPayload } from "./models/ConfirmRegistrationPayload"; -export type { CreateInvitePayload } from "./models/CreateInvitePayload"; -export type { DeleteSessionPayload } from "./models/DeleteSessionPayload"; -export type { FileAttachment } from "./models/FileAttachment"; -export type { Group } from "./models/Group"; -export type { GroupInvite } from "./models/GroupInvite"; -export type { GroupLog } from "./models/GroupLog"; -export type { GroupMember } from "./models/GroupMember"; -export type { GroupMessage } from "./models/GroupMessage"; -export type { GroupPayload } from "./models/GroupPayload"; -export type { GroupPreview } from "./models/GroupPreview"; -export type { HTTPValidationError } from "./models/HTTPValidationError"; -export type { LoginPayload } from "./models/LoginPayload"; -export type { NewAccount } from "./models/NewAccount"; -export type { NewFile } from "./models/NewFile"; -export type { NewTransaction } from "./models/NewTransaction"; -export type { NewTransactionPosition } from "./models/NewTransactionPosition"; -export type { PersonalAccount } from "./models/PersonalAccount"; -export type { PreviewGroupPayload } from "./models/PreviewGroupPayload"; -export type { RecoverPasswordPayload } from "./models/RecoverPasswordPayload"; -export type { RegisterPayload } from "./models/RegisterPayload"; -export type { RegisterResponse } from "./models/RegisterResponse"; -export type { RenameSessionPayload } from "./models/RenameSessionPayload"; -export type { Session } from "./models/Session"; -export type { Token } from "./models/Token"; -export type { Transaction } from "./models/Transaction"; -export type { TransactionPosition } from "./models/TransactionPosition"; -export type { TransactionType } from "./models/TransactionType"; -export type { UpdateFile } from "./models/UpdateFile"; -export type { UpdateGroupMemberPayload } from "./models/UpdateGroupMemberPayload"; -export type { UpdatePositionsPayload } from "./models/UpdatePositionsPayload"; -export type { UpdateTransaction } from "./models/UpdateTransaction"; -export type { User } from "./models/User"; -export type { ValidationError } from "./models/ValidationError"; -export type { VersionResponse } from "./models/VersionResponse"; +export type { AccountType } from './models/AccountType'; +export type { Body_get_token } from './models/Body_get_token'; +export type { ChangeEmailPayload } from './models/ChangeEmailPayload'; +export type { ChangePasswordPayload } from './models/ChangePasswordPayload'; +export type { ClearingAccount } from './models/ClearingAccount'; +export type { ConfirmEmailChangePayload } from './models/ConfirmEmailChangePayload'; +export type { ConfirmPasswordRecoveryPayload } from './models/ConfirmPasswordRecoveryPayload'; +export type { ConfirmRegistrationPayload } from './models/ConfirmRegistrationPayload'; +export type { CreateInvitePayload } from './models/CreateInvitePayload'; +export type { DeleteSessionPayload } from './models/DeleteSessionPayload'; +export type { FileAttachment } from './models/FileAttachment'; +export type { Group } from './models/Group'; +export type { GroupInvite } from './models/GroupInvite'; +export type { GroupLog } from './models/GroupLog'; +export type { GroupMember } from './models/GroupMember'; +export type { GroupMessage } from './models/GroupMessage'; +export type { GroupPayload } from './models/GroupPayload'; +export type { GroupPreview } from './models/GroupPreview'; +export type { HTTPValidationError } from './models/HTTPValidationError'; +export type { LoginPayload } from './models/LoginPayload'; +export type { NewAccount } from './models/NewAccount'; +export type { NewFile } from './models/NewFile'; +export type { NewTransaction } from './models/NewTransaction'; +export type { NewTransactionPosition } from './models/NewTransactionPosition'; +export type { PersonalAccount } from './models/PersonalAccount'; +export type { PreviewGroupPayload } from './models/PreviewGroupPayload'; +export type { RecoverPasswordPayload } from './models/RecoverPasswordPayload'; +export type { RegisterPayload } from './models/RegisterPayload'; +export type { RegisterResponse } from './models/RegisterResponse'; +export type { RenameSessionPayload } from './models/RenameSessionPayload'; +export type { Session } from './models/Session'; +export type { Token } from './models/Token'; +export type { Transaction } from './models/Transaction'; +export type { TransactionPosition } from './models/TransactionPosition'; +export type { TransactionType } from './models/TransactionType'; +export type { UpdateFile } from './models/UpdateFile'; +export type { UpdateGroupMemberPayload } from './models/UpdateGroupMemberPayload'; +export type { UpdatePositionsPayload } from './models/UpdatePositionsPayload'; +export type { UpdateTransaction } from './models/UpdateTransaction'; +export type { User } from './models/User'; +export type { ValidationError } from './models/ValidationError'; +export type { VersionResponse } from './models/VersionResponse'; -export { AccountsService } from "./services/AccountsService"; -export { AuthService } from "./services/AuthService"; -export { CommonService } from "./services/CommonService"; -export { GroupsService } from "./services/GroupsService"; -export { TransactionsService } from "./services/TransactionsService"; +export { AccountsService } from './services/AccountsService'; +export { AuthService } from './services/AuthService'; +export { CommonService } from './services/CommonService'; +export { GroupsService } from './services/GroupsService'; +export { TransactionsService } from './services/TransactionsService'; diff --git a/frontend/libs/api/src/lib/generated/models/AccountType.ts b/frontend/libs/api/src/lib/generated/models/AccountType.ts index c6625c0..63dd523 100644 --- a/frontend/libs/api/src/lib/generated/models/AccountType.ts +++ b/frontend/libs/api/src/lib/generated/models/AccountType.ts @@ -1,6 +1,5 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - -export type AccountType = "personal" | "clearing"; +export type AccountType = 'personal' | 'clearing'; diff --git a/frontend/libs/api/src/lib/generated/models/Body_get_token.ts b/frontend/libs/api/src/lib/generated/models/Body_get_token.ts index 5ee3696..7ab1d61 100644 --- a/frontend/libs/api/src/lib/generated/models/Body_get_token.ts +++ b/frontend/libs/api/src/lib/generated/models/Body_get_token.ts @@ -1,13 +1,13 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type Body_get_token = { - grant_type?: string | null; + grant_type?: (string | null); username: string; password: string; scope?: string; - client_id?: string | null; - client_secret?: string | null; + client_id?: (string | null); + client_secret?: (string | null); }; + diff --git a/frontend/libs/api/src/lib/generated/models/ChangeEmailPayload.ts b/frontend/libs/api/src/lib/generated/models/ChangeEmailPayload.ts index 5f9ad26..21c9bf3 100644 --- a/frontend/libs/api/src/lib/generated/models/ChangeEmailPayload.ts +++ b/frontend/libs/api/src/lib/generated/models/ChangeEmailPayload.ts @@ -1,9 +1,9 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type ChangeEmailPayload = { email: string; password: string; }; + diff --git a/frontend/libs/api/src/lib/generated/models/ChangePasswordPayload.ts b/frontend/libs/api/src/lib/generated/models/ChangePasswordPayload.ts index 357b527..bffab57 100644 --- a/frontend/libs/api/src/lib/generated/models/ChangePasswordPayload.ts +++ b/frontend/libs/api/src/lib/generated/models/ChangePasswordPayload.ts @@ -1,9 +1,9 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type ChangePasswordPayload = { new_password: string; old_password: string; }; + diff --git a/frontend/libs/api/src/lib/generated/models/ClearingAccount.ts b/frontend/libs/api/src/lib/generated/models/ClearingAccount.ts index 0ca87f0..21f6739 100644 --- a/frontend/libs/api/src/lib/generated/models/ClearingAccount.ts +++ b/frontend/libs/api/src/lib/generated/models/ClearingAccount.ts @@ -1,8 +1,7 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type ClearingAccount = { id: number; group_id: number; @@ -15,3 +14,4 @@ export type ClearingAccount = { last_changed: string; deleted: boolean; }; + diff --git a/frontend/libs/api/src/lib/generated/models/ConfirmEmailChangePayload.ts b/frontend/libs/api/src/lib/generated/models/ConfirmEmailChangePayload.ts index ab7637b..ad09f94 100644 --- a/frontend/libs/api/src/lib/generated/models/ConfirmEmailChangePayload.ts +++ b/frontend/libs/api/src/lib/generated/models/ConfirmEmailChangePayload.ts @@ -1,8 +1,8 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type ConfirmEmailChangePayload = { token: string; }; + diff --git a/frontend/libs/api/src/lib/generated/models/ConfirmPasswordRecoveryPayload.ts b/frontend/libs/api/src/lib/generated/models/ConfirmPasswordRecoveryPayload.ts index 251a6aa..64d4a5c 100644 --- a/frontend/libs/api/src/lib/generated/models/ConfirmPasswordRecoveryPayload.ts +++ b/frontend/libs/api/src/lib/generated/models/ConfirmPasswordRecoveryPayload.ts @@ -1,9 +1,9 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type ConfirmPasswordRecoveryPayload = { token: string; new_password: string; }; + diff --git a/frontend/libs/api/src/lib/generated/models/ConfirmRegistrationPayload.ts b/frontend/libs/api/src/lib/generated/models/ConfirmRegistrationPayload.ts index 5af08a3..6970d70 100644 --- a/frontend/libs/api/src/lib/generated/models/ConfirmRegistrationPayload.ts +++ b/frontend/libs/api/src/lib/generated/models/ConfirmRegistrationPayload.ts @@ -1,8 +1,8 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type ConfirmRegistrationPayload = { token: string; }; + diff --git a/frontend/libs/api/src/lib/generated/models/CreateInvitePayload.ts b/frontend/libs/api/src/lib/generated/models/CreateInvitePayload.ts index 02a5ff0..94d4b11 100644 --- a/frontend/libs/api/src/lib/generated/models/CreateInvitePayload.ts +++ b/frontend/libs/api/src/lib/generated/models/CreateInvitePayload.ts @@ -1,11 +1,11 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type CreateInvitePayload = { description: string; single_use: boolean; join_as_editor: boolean; valid_until: string; }; + diff --git a/frontend/libs/api/src/lib/generated/models/DeleteSessionPayload.ts b/frontend/libs/api/src/lib/generated/models/DeleteSessionPayload.ts index 194739f..34fbafd 100644 --- a/frontend/libs/api/src/lib/generated/models/DeleteSessionPayload.ts +++ b/frontend/libs/api/src/lib/generated/models/DeleteSessionPayload.ts @@ -1,8 +1,8 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type DeleteSessionPayload = { session_id: number; }; + diff --git a/frontend/libs/api/src/lib/generated/models/FileAttachment.ts b/frontend/libs/api/src/lib/generated/models/FileAttachment.ts index 0c15bec..15b949a 100644 --- a/frontend/libs/api/src/lib/generated/models/FileAttachment.ts +++ b/frontend/libs/api/src/lib/generated/models/FileAttachment.ts @@ -1,13 +1,13 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type FileAttachment = { id: number; filename: string; - blob_id: number | null; - mime_type: string | null; - host_url?: string | null; + blob_id: (number | null); + mime_type: (string | null); + host_url?: (string | null); deleted: boolean; }; + diff --git a/frontend/libs/api/src/lib/generated/models/Group.ts b/frontend/libs/api/src/lib/generated/models/Group.ts index 13c5356..7409c7c 100644 --- a/frontend/libs/api/src/lib/generated/models/Group.ts +++ b/frontend/libs/api/src/lib/generated/models/Group.ts @@ -1,8 +1,7 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type Group = { id: number; name: string; @@ -12,4 +11,7 @@ export type Group = { add_user_account_on_join: boolean; created_at: string; created_by: number; + last_changed: string; + archived: boolean; }; + diff --git a/frontend/libs/api/src/lib/generated/models/GroupInvite.ts b/frontend/libs/api/src/lib/generated/models/GroupInvite.ts index c2269e5..ed8164e 100644 --- a/frontend/libs/api/src/lib/generated/models/GroupInvite.ts +++ b/frontend/libs/api/src/lib/generated/models/GroupInvite.ts @@ -1,14 +1,14 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type GroupInvite = { id: number; created_by: number; - token: string | null; + token: (string | null); single_use: boolean; join_as_editor: boolean; description: string; valid_until: string; }; + diff --git a/frontend/libs/api/src/lib/generated/models/GroupLog.ts b/frontend/libs/api/src/lib/generated/models/GroupLog.ts index a2a727c..cb6aa8f 100644 --- a/frontend/libs/api/src/lib/generated/models/GroupLog.ts +++ b/frontend/libs/api/src/lib/generated/models/GroupLog.ts @@ -1,13 +1,13 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type GroupLog = { id: number; user_id: number; logged_at: string; type: string; message: string; - affected: number | null; + affected: (number | null); }; + diff --git a/frontend/libs/api/src/lib/generated/models/GroupMember.ts b/frontend/libs/api/src/lib/generated/models/GroupMember.ts index d6b4ecd..a982c1d 100644 --- a/frontend/libs/api/src/lib/generated/models/GroupMember.ts +++ b/frontend/libs/api/src/lib/generated/models/GroupMember.ts @@ -1,8 +1,7 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type GroupMember = { user_id: number; username: string; @@ -10,5 +9,6 @@ export type GroupMember = { can_write: boolean; description: string; joined_at: string; - invited_by: number | null; + invited_by: (number | null); }; + diff --git a/frontend/libs/api/src/lib/generated/models/GroupMessage.ts b/frontend/libs/api/src/lib/generated/models/GroupMessage.ts index 5f896e3..2548d76 100644 --- a/frontend/libs/api/src/lib/generated/models/GroupMessage.ts +++ b/frontend/libs/api/src/lib/generated/models/GroupMessage.ts @@ -1,8 +1,8 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type GroupMessage = { message: string; }; + diff --git a/frontend/libs/api/src/lib/generated/models/GroupPayload.ts b/frontend/libs/api/src/lib/generated/models/GroupPayload.ts index 841817b..f35e3f1 100644 --- a/frontend/libs/api/src/lib/generated/models/GroupPayload.ts +++ b/frontend/libs/api/src/lib/generated/models/GroupPayload.ts @@ -1,8 +1,7 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type GroupPayload = { name: string; description?: string; @@ -10,3 +9,4 @@ export type GroupPayload = { add_user_account_on_join?: boolean; terms?: string; }; + diff --git a/frontend/libs/api/src/lib/generated/models/GroupPreview.ts b/frontend/libs/api/src/lib/generated/models/GroupPreview.ts index 99d266c..3ce1da7 100644 --- a/frontend/libs/api/src/lib/generated/models/GroupPreview.ts +++ b/frontend/libs/api/src/lib/generated/models/GroupPreview.ts @@ -1,8 +1,7 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type GroupPreview = { id: number; name: string; @@ -14,3 +13,4 @@ export type GroupPreview = { invite_valid_until: string; invite_description: string; }; + diff --git a/frontend/libs/api/src/lib/generated/models/HTTPValidationError.ts b/frontend/libs/api/src/lib/generated/models/HTTPValidationError.ts index 247aced..f9b1a79 100644 --- a/frontend/libs/api/src/lib/generated/models/HTTPValidationError.ts +++ b/frontend/libs/api/src/lib/generated/models/HTTPValidationError.ts @@ -1,10 +1,9 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - -import type { ValidationError } from "./ValidationError"; - +import type { ValidationError } from './ValidationError'; export type HTTPValidationError = { detail?: Array; }; + diff --git a/frontend/libs/api/src/lib/generated/models/LoginPayload.ts b/frontend/libs/api/src/lib/generated/models/LoginPayload.ts index 4543d5a..035ef4e 100644 --- a/frontend/libs/api/src/lib/generated/models/LoginPayload.ts +++ b/frontend/libs/api/src/lib/generated/models/LoginPayload.ts @@ -1,10 +1,10 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type LoginPayload = { username: string; password: string; session_name: string; }; + diff --git a/frontend/libs/api/src/lib/generated/models/NewAccount.ts b/frontend/libs/api/src/lib/generated/models/NewAccount.ts index fd10051..146d98d 100644 --- a/frontend/libs/api/src/lib/generated/models/NewAccount.ts +++ b/frontend/libs/api/src/lib/generated/models/NewAccount.ts @@ -1,17 +1,16 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - -import type { AccountType } from "./AccountType"; - +import type { AccountType } from './AccountType'; export type NewAccount = { type: AccountType; name: string; description?: string; - owning_user_id?: number | null; - date_info?: string | null; + owning_user_id?: (number | null); + date_info?: (string | null); deleted?: boolean; tags?: Array; clearing_shares?: Record; }; + diff --git a/frontend/libs/api/src/lib/generated/models/NewFile.ts b/frontend/libs/api/src/lib/generated/models/NewFile.ts index b870620..53c8afc 100644 --- a/frontend/libs/api/src/lib/generated/models/NewFile.ts +++ b/frontend/libs/api/src/lib/generated/models/NewFile.ts @@ -1,10 +1,10 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type NewFile = { filename: string; mime_type: string; content: string; }; + diff --git a/frontend/libs/api/src/lib/generated/models/NewTransaction.ts b/frontend/libs/api/src/lib/generated/models/NewTransaction.ts index 79f1817..ee0e5e2 100644 --- a/frontend/libs/api/src/lib/generated/models/NewTransaction.ts +++ b/frontend/libs/api/src/lib/generated/models/NewTransaction.ts @@ -1,12 +1,10 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - -import type { NewFile } from "./NewFile"; -import type { NewTransactionPosition } from "./NewTransactionPosition"; -import type { TransactionType } from "./TransactionType"; - +import type { NewFile } from './NewFile'; +import type { NewTransactionPosition } from './NewTransactionPosition'; +import type { TransactionType } from './TransactionType'; export type NewTransaction = { type: TransactionType; name: string; @@ -21,3 +19,4 @@ export type NewTransaction = { new_files?: Array; new_positions?: Array; }; + diff --git a/frontend/libs/api/src/lib/generated/models/NewTransactionPosition.ts b/frontend/libs/api/src/lib/generated/models/NewTransactionPosition.ts index 6465ec3..99ad220 100644 --- a/frontend/libs/api/src/lib/generated/models/NewTransactionPosition.ts +++ b/frontend/libs/api/src/lib/generated/models/NewTransactionPosition.ts @@ -1,11 +1,11 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type NewTransactionPosition = { name: string; price: number; communist_shares: number; usages: Record; }; + diff --git a/frontend/libs/api/src/lib/generated/models/PersonalAccount.ts b/frontend/libs/api/src/lib/generated/models/PersonalAccount.ts index 1ed80ea..148b7cc 100644 --- a/frontend/libs/api/src/lib/generated/models/PersonalAccount.ts +++ b/frontend/libs/api/src/lib/generated/models/PersonalAccount.ts @@ -1,15 +1,15 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type PersonalAccount = { id: number; group_id: number; type: "personal"; name: string; description: string; - owning_user_id: number | null; + owning_user_id: (number | null); deleted: boolean; last_changed: string; }; + diff --git a/frontend/libs/api/src/lib/generated/models/PreviewGroupPayload.ts b/frontend/libs/api/src/lib/generated/models/PreviewGroupPayload.ts index 57d9d8e..a5cb699 100644 --- a/frontend/libs/api/src/lib/generated/models/PreviewGroupPayload.ts +++ b/frontend/libs/api/src/lib/generated/models/PreviewGroupPayload.ts @@ -1,8 +1,8 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type PreviewGroupPayload = { invite_token: string; }; + diff --git a/frontend/libs/api/src/lib/generated/models/RecoverPasswordPayload.ts b/frontend/libs/api/src/lib/generated/models/RecoverPasswordPayload.ts index eddd6f9..0ac385d 100644 --- a/frontend/libs/api/src/lib/generated/models/RecoverPasswordPayload.ts +++ b/frontend/libs/api/src/lib/generated/models/RecoverPasswordPayload.ts @@ -1,8 +1,8 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type RecoverPasswordPayload = { email: string; }; + diff --git a/frontend/libs/api/src/lib/generated/models/RegisterPayload.ts b/frontend/libs/api/src/lib/generated/models/RegisterPayload.ts index 3567ff5..81ec193 100644 --- a/frontend/libs/api/src/lib/generated/models/RegisterPayload.ts +++ b/frontend/libs/api/src/lib/generated/models/RegisterPayload.ts @@ -1,11 +1,11 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type RegisterPayload = { username: string; password: string; email: string; - invite_token?: string | null; + invite_token?: (string | null); }; + diff --git a/frontend/libs/api/src/lib/generated/models/RegisterResponse.ts b/frontend/libs/api/src/lib/generated/models/RegisterResponse.ts index 0082e82..1d6a4e9 100644 --- a/frontend/libs/api/src/lib/generated/models/RegisterResponse.ts +++ b/frontend/libs/api/src/lib/generated/models/RegisterResponse.ts @@ -1,8 +1,8 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type RegisterResponse = { user_id: number; }; + diff --git a/frontend/libs/api/src/lib/generated/models/RenameSessionPayload.ts b/frontend/libs/api/src/lib/generated/models/RenameSessionPayload.ts index 49ec11e..5a3e2a1 100644 --- a/frontend/libs/api/src/lib/generated/models/RenameSessionPayload.ts +++ b/frontend/libs/api/src/lib/generated/models/RenameSessionPayload.ts @@ -1,9 +1,9 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type RenameSessionPayload = { session_id: number; name: string; }; + diff --git a/frontend/libs/api/src/lib/generated/models/Session.ts b/frontend/libs/api/src/lib/generated/models/Session.ts index 296c6d5..1bb0dea 100644 --- a/frontend/libs/api/src/lib/generated/models/Session.ts +++ b/frontend/libs/api/src/lib/generated/models/Session.ts @@ -1,11 +1,11 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type Session = { id: number; name: string; - valid_until: string | null; + valid_until: (string | null); last_seen: string; }; + diff --git a/frontend/libs/api/src/lib/generated/models/Token.ts b/frontend/libs/api/src/lib/generated/models/Token.ts index d5b6846..e4dcb7c 100644 --- a/frontend/libs/api/src/lib/generated/models/Token.ts +++ b/frontend/libs/api/src/lib/generated/models/Token.ts @@ -1,9 +1,9 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type Token = { user_id: number; access_token: string; }; + diff --git a/frontend/libs/api/src/lib/generated/models/Transaction.ts b/frontend/libs/api/src/lib/generated/models/Transaction.ts index 0b43df8..fd305df 100644 --- a/frontend/libs/api/src/lib/generated/models/Transaction.ts +++ b/frontend/libs/api/src/lib/generated/models/Transaction.ts @@ -1,12 +1,10 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - -import type { FileAttachment } from "./FileAttachment"; -import type { TransactionPosition } from "./TransactionPosition"; -import type { TransactionType } from "./TransactionType"; - +import type { FileAttachment } from './FileAttachment'; +import type { TransactionPosition } from './TransactionPosition'; +import type { TransactionType } from './TransactionType'; export type Transaction = { id: number; group_id: number; @@ -25,3 +23,4 @@ export type Transaction = { positions: Array; files: Array; }; + diff --git a/frontend/libs/api/src/lib/generated/models/TransactionPosition.ts b/frontend/libs/api/src/lib/generated/models/TransactionPosition.ts index 7610050..d63eacf 100644 --- a/frontend/libs/api/src/lib/generated/models/TransactionPosition.ts +++ b/frontend/libs/api/src/lib/generated/models/TransactionPosition.ts @@ -1,8 +1,7 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type TransactionPosition = { name: string; price: number; @@ -11,3 +10,4 @@ export type TransactionPosition = { id: number; deleted: boolean; }; + diff --git a/frontend/libs/api/src/lib/generated/models/TransactionType.ts b/frontend/libs/api/src/lib/generated/models/TransactionType.ts index dd07b53..53631cd 100644 --- a/frontend/libs/api/src/lib/generated/models/TransactionType.ts +++ b/frontend/libs/api/src/lib/generated/models/TransactionType.ts @@ -1,6 +1,5 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - -export type TransactionType = "mimo" | "purchase" | "transfer"; +export type TransactionType = 'mimo' | 'purchase' | 'transfer'; diff --git a/frontend/libs/api/src/lib/generated/models/UpdateFile.ts b/frontend/libs/api/src/lib/generated/models/UpdateFile.ts index cd3b51d..226ff3a 100644 --- a/frontend/libs/api/src/lib/generated/models/UpdateFile.ts +++ b/frontend/libs/api/src/lib/generated/models/UpdateFile.ts @@ -1,10 +1,10 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type UpdateFile = { id: number; filename: string; deleted: boolean; }; + diff --git a/frontend/libs/api/src/lib/generated/models/UpdateGroupMemberPayload.ts b/frontend/libs/api/src/lib/generated/models/UpdateGroupMemberPayload.ts index 8546900..ff21e66 100644 --- a/frontend/libs/api/src/lib/generated/models/UpdateGroupMemberPayload.ts +++ b/frontend/libs/api/src/lib/generated/models/UpdateGroupMemberPayload.ts @@ -1,10 +1,10 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type UpdateGroupMemberPayload = { user_id: number; can_write: boolean; is_owner: boolean; }; + diff --git a/frontend/libs/api/src/lib/generated/models/UpdatePositionsPayload.ts b/frontend/libs/api/src/lib/generated/models/UpdatePositionsPayload.ts index e7db6b8..f53a37f 100644 --- a/frontend/libs/api/src/lib/generated/models/UpdatePositionsPayload.ts +++ b/frontend/libs/api/src/lib/generated/models/UpdatePositionsPayload.ts @@ -1,10 +1,9 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - -import type { TransactionPosition } from "./TransactionPosition"; - +import type { TransactionPosition } from './TransactionPosition'; export type UpdatePositionsPayload = { positions: Array; }; + diff --git a/frontend/libs/api/src/lib/generated/models/UpdateTransaction.ts b/frontend/libs/api/src/lib/generated/models/UpdateTransaction.ts index bee2578..e5cb822 100644 --- a/frontend/libs/api/src/lib/generated/models/UpdateTransaction.ts +++ b/frontend/libs/api/src/lib/generated/models/UpdateTransaction.ts @@ -1,14 +1,12 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - -import type { NewFile } from "./NewFile"; -import type { NewTransactionPosition } from "./NewTransactionPosition"; -import type { TransactionPosition } from "./TransactionPosition"; -import type { TransactionType } from "./TransactionType"; -import type { UpdateFile } from "./UpdateFile"; - +import type { NewFile } from './NewFile'; +import type { NewTransactionPosition } from './NewTransactionPosition'; +import type { TransactionPosition } from './TransactionPosition'; +import type { TransactionType } from './TransactionType'; +import type { UpdateFile } from './UpdateFile'; export type UpdateTransaction = { type: TransactionType; name: string; @@ -25,3 +23,4 @@ export type UpdateTransaction = { changed_files?: Array; changed_positions?: Array; }; + diff --git a/frontend/libs/api/src/lib/generated/models/User.ts b/frontend/libs/api/src/lib/generated/models/User.ts index 3a5409f..31df3aa 100644 --- a/frontend/libs/api/src/lib/generated/models/User.ts +++ b/frontend/libs/api/src/lib/generated/models/User.ts @@ -1,10 +1,8 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - -import type { Session } from "./Session"; - +import type { Session } from './Session'; export type User = { id: number; username: string; @@ -15,3 +13,4 @@ export type User = { sessions: Array; is_guest_user: boolean; }; + diff --git a/frontend/libs/api/src/lib/generated/models/ValidationError.ts b/frontend/libs/api/src/lib/generated/models/ValidationError.ts index b9c2f17..aaf1c92 100644 --- a/frontend/libs/api/src/lib/generated/models/ValidationError.ts +++ b/frontend/libs/api/src/lib/generated/models/ValidationError.ts @@ -1,10 +1,10 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type ValidationError = { - loc: Array; + loc: Array<(string | number)>; msg: string; type: string; }; + diff --git a/frontend/libs/api/src/lib/generated/models/VersionResponse.ts b/frontend/libs/api/src/lib/generated/models/VersionResponse.ts index 8c07761..7e1ba3d 100644 --- a/frontend/libs/api/src/lib/generated/models/VersionResponse.ts +++ b/frontend/libs/api/src/lib/generated/models/VersionResponse.ts @@ -1,11 +1,11 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ - export type VersionResponse = { version: string; major_version: number; minor_version: number; patch_version: number; }; + diff --git a/frontend/libs/api/src/lib/generated/schema.ts b/frontend/libs/api/src/lib/generated/schema.ts index 1a952d4..a866219 100644 --- a/frontend/libs/api/src/lib/generated/schema.ts +++ b/frontend/libs/api/src/lib/generated/schema.ts @@ -6,1514 +6,1573 @@ * Do not make direct changes to the file. */ -import { z } from "zod"; + +import { z } from 'zod'; export namespace components.schemas { - /** - * AccountType - * @enum {string} - */ - export const AccountType = z.enum(["personal", "clearing"]); - /** Body_get_token */ - export const Body_get_token = z.object({ - grant_type: z.union([z.string(), z.null()]).optional(), - username: z.string(), - password: z.string(), - scope: z.string().optional(), - client_id: z.union([z.string(), z.null()]).optional(), - client_secret: z.union([z.string(), z.null()]).optional(), - }); - /** ChangeEmailPayload */ - export const ChangeEmailPayload = z.object({ - email: z.string(), - password: z.string(), - }); - /** ChangePasswordPayload */ - export const ChangePasswordPayload = z.object({ - new_password: z.string(), - old_password: z.string(), - }); - /** ClearingAccount */ - export const ClearingAccount = z.object({ - id: z.number().int(), + /** + * AccountType + * @enum {string} + */ + export const AccountType = z.enum(["personal", "clearing"]); + /** Body_get_token */ + export const Body_get_token = z.object({ + grant_type: z.union([z.string(), z.null()]).optional(), + username: z.string(), + password: z.string(), + scope: z.string().optional(), + client_id: z.union([z.string(), z.null()]).optional(), + client_secret: z.union([z.string(), z.null()]).optional(), + }); + /** ChangeEmailPayload */ + export const ChangeEmailPayload = z.object({ + email: z.string(), + password: z.string(), + }); + /** ChangePasswordPayload */ + export const ChangePasswordPayload = z.object({ + new_password: z.string(), + old_password: z.string(), + }); + /** ClearingAccount */ + export const ClearingAccount = z.object({ + id: z.number().int(), + group_id: z.number().int(), + type: z.literal("clearing"), + name: z.string(), + description: z.string(), + date_info: z.string(), + tags: z.array(z.string()), + clearing_shares: z.record(z.number()), + last_changed: z.string(), + deleted: z.boolean(), + }); + /** ConfirmEmailChangePayload */ + export const ConfirmEmailChangePayload = z.object({ + token: z.string(), + }); + /** ConfirmPasswordRecoveryPayload */ + export const ConfirmPasswordRecoveryPayload = z.object({ + token: z.string(), + new_password: z.string(), + }); + /** ConfirmRegistrationPayload */ + export const ConfirmRegistrationPayload = z.object({ + token: z.string(), + }); + /** CreateInvitePayload */ + export const CreateInvitePayload = z.object({ + description: z.string(), + single_use: z.boolean(), + join_as_editor: z.boolean(), + valid_until: z.string(), + }); + /** DeleteSessionPayload */ + export const DeleteSessionPayload = z.object({ + session_id: z.number().int(), + }); + /** FileAttachment */ + export const FileAttachment = z.object({ + id: z.number().int(), + filename: z.string(), + blob_id: z.union([z.number().int(), z.null()]), + mime_type: z.union([z.string(), z.null()]), + host_url: z.union([z.string(), z.null()]).optional(), + deleted: z.boolean(), + }); + /** Group */ + export const Group = z.object({ + id: z.number().int(), + name: z.string(), + description: z.string(), + currency_symbol: z.string(), + terms: z.string(), + add_user_account_on_join: z.boolean(), + created_at: z.string(), + created_by: z.number().int(), + last_changed: z.string(), + archived: z.boolean(), + }); + /** GroupInvite */ + export const GroupInvite = z.object({ + id: z.number().int(), + created_by: z.number().int(), + token: z.union([z.string(), z.null()]), + single_use: z.boolean(), + join_as_editor: z.boolean(), + description: z.string(), + valid_until: z.string(), + }); + /** GroupLog */ + export const GroupLog = z.object({ + id: z.number().int(), + user_id: z.number().int(), + logged_at: z.string(), + type: z.string(), + message: z.string(), + affected: z.union([z.number().int(), z.null()]), + }); + /** GroupMember */ + export const GroupMember = z.object({ + user_id: z.number().int(), + username: z.string(), + is_owner: z.boolean(), + can_write: z.boolean(), + description: z.string(), + joined_at: z.string(), + invited_by: z.union([z.number().int(), z.null()]), + }); + /** GroupMessage */ + export const GroupMessage = z.object({ + message: z.string(), + }); + /** GroupPayload */ + export const GroupPayload = z.object({ + name: z.string(), + description: z.string().optional(), + currency_symbol: z.string(), + add_user_account_on_join: z.boolean().optional(), + terms: z.string().optional(), + }); + /** GroupPreview */ + export const GroupPreview = z.object({ + id: z.number().int(), + name: z.string(), + description: z.string(), + currency_symbol: z.string(), + terms: z.string(), + created_at: z.string(), + invite_single_use: z.boolean(), + invite_valid_until: z.string(), + invite_description: z.string(), + }); + /** HTTPValidationError */ + export const HTTPValidationError = z.object({ + detail: z.array(components["schemas"]["ValidationError"]).optional(), + }); + /** LoginPayload */ + export const LoginPayload = z.object({ + username: z.string(), + password: z.string(), + session_name: z.string(), + }); + /** NewAccount */ + export const NewAccount = z.object({ + type: components["schemas"]["AccountType"], + name: z.string(), + description: z.string().optional(), + owning_user_id: z.union([z.number().int(), z.null()]).optional(), + date_info: z.union([z.string(), z.null()]).optional(), + deleted: z.boolean().optional(), + tags: z.array(z.string()).optional(), + clearing_shares: z.record(z.number()).optional(), + }); + /** NewFile */ + export const NewFile = z.object({ + filename: z.string(), + mime_type: z.string(), + content: z.string(), + }); + /** NewTransaction */ + export const NewTransaction = z.object({ + type: components["schemas"]["TransactionType"], + name: z.string(), + description: z.string(), + value: z.number(), + currency_symbol: z.string(), + currency_conversion_rate: z.number(), + billed_at: z.string(), + tags: z.array(z.string()).optional(), + creditor_shares: z.record(z.number()), + debitor_shares: z.record(z.number()), + new_files: z.array(components["schemas"]["NewFile"]).optional(), + new_positions: z.array(components["schemas"]["NewTransactionPosition"]).optional(), + }); + /** NewTransactionPosition */ + export const NewTransactionPosition = z.object({ + name: z.string(), + price: z.number(), + communist_shares: z.number(), + usages: z.record(z.number()), + }); + /** PersonalAccount */ + export const PersonalAccount = z.object({ + id: z.number().int(), + group_id: z.number().int(), + type: z.literal("personal"), + name: z.string(), + description: z.string(), + owning_user_id: z.union([z.number().int(), z.null()]), + deleted: z.boolean(), + last_changed: z.string(), + }); + /** PreviewGroupPayload */ + export const PreviewGroupPayload = z.object({ + invite_token: z.string(), + }); + /** RecoverPasswordPayload */ + export const RecoverPasswordPayload = z.object({ + email: z.string(), + }); + /** RegisterPayload */ + export const RegisterPayload = z.object({ + username: z.string(), + password: z.string(), + email: z.string(), + invite_token: z.union([z.string(), z.null()]).optional(), + }); + /** RegisterResponse */ + export const RegisterResponse = z.object({ + user_id: z.number().int(), + }); + /** RenameSessionPayload */ + export const RenameSessionPayload = z.object({ + session_id: z.number().int(), + name: z.string(), + }); + /** Session */ + export const Session = z.object({ + id: z.number().int(), + name: z.string(), + valid_until: z.union([z.string(), z.null()]), + last_seen: z.string(), + }); + /** Token */ + export const Token = z.object({ + user_id: z.number().int(), + access_token: z.string(), + }); + /** Transaction */ + export const Transaction = z.object({ + id: z.number().int(), + group_id: z.number().int(), + type: components["schemas"]["TransactionType"], + name: z.string(), + description: z.string(), + value: z.number(), + currency_symbol: z.string(), + currency_conversion_rate: z.number(), + billed_at: z.string(), + tags: z.array(z.string()), + deleted: z.boolean(), + creditor_shares: z.record(z.number()), + debitor_shares: z.record(z.number()), + last_changed: z.string(), + positions: z.array(components["schemas"]["TransactionPosition"]), + files: z.array(components["schemas"]["FileAttachment"]), + }); + /** TransactionPosition */ + export const TransactionPosition = z.object({ + name: z.string(), + price: z.number(), + communist_shares: z.number(), + usages: z.record(z.number()), + id: z.number().int(), + deleted: z.boolean(), + }); + /** + * TransactionType + * @enum {string} + */ + export const TransactionType = z.enum(["mimo", "purchase", "transfer"]); + /** UpdateFile */ + export const UpdateFile = z.object({ + id: z.number().int(), + filename: z.string(), + deleted: z.boolean(), + }); + /** UpdateGroupMemberPayload */ + export const UpdateGroupMemberPayload = z.object({ + user_id: z.number().int(), + can_write: z.boolean(), + is_owner: z.boolean(), + }); + /** UpdatePositionsPayload */ + export const UpdatePositionsPayload = z.object({ + positions: z.array(components["schemas"]["TransactionPosition"]), + }); + /** UpdateTransaction */ + export const UpdateTransaction = z.object({ + type: components["schemas"]["TransactionType"], + name: z.string(), + description: z.string(), + value: z.number(), + currency_symbol: z.string(), + currency_conversion_rate: z.number(), + billed_at: z.string(), + tags: z.array(z.string()).optional(), + creditor_shares: z.record(z.number()), + debitor_shares: z.record(z.number()), + new_files: z.array(components["schemas"]["NewFile"]).optional(), + new_positions: z.array(components["schemas"]["NewTransactionPosition"]).optional(), + changed_files: z.array(components["schemas"]["UpdateFile"]).optional(), + changed_positions: z.array(components["schemas"]["TransactionPosition"]).optional(), + }); + /** User */ + export const User = z.object({ + id: z.number().int(), + username: z.string(), + email: z.string(), + registered_at: z.string(), + deleted: z.boolean(), + pending: z.boolean(), + sessions: z.array(components["schemas"]["Session"]), + is_guest_user: z.boolean(), + }); + /** ValidationError */ + export const ValidationError = z.object({ + loc: z.array(z.union([z.string(), z.number().int()])), + msg: z.string(), + type: z.string(), + }); + /** + * VersionResponse + * @example { + * "major_version": 1, + * "minor_version": 3, + * "patch_version": 2, + * "version": "1.3.2" + * } + */ + export const VersionResponse = z.object({ + version: z.string(), + major_version: z.number().int(), + minor_version: z.number().int(), + patch_version: z.number().int(), + }); +} + +export const operations = { + + list_transactions: { + /** list all transactions in a group */ + parameters: { + query: z.object({ + min_last_changed: z.union([z.string(), z.null()]).optional(), + transaction_ids: z.union([z.string(), z.null()]).optional(), + }).optional(), + path: z.object({ + group_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": z.array(components["schemas"]["Transaction"]), + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + create_transaction: { + /** create a new transaction */ + parameters: { + path: z.object({ + group_id: z.number().int(), + }), + }, + requestBody: { + content: { + "application/json": components["schemas"]["NewTransaction"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["Transaction"], + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + get_transaction: { + /** get transaction details */ + parameters: { + path: z.object({ + group_id: z.number().int(), + transaction_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["Transaction"], + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + update_transaction: { + /** update transaction details */ + parameters: { + path: z.object({ + group_id: z.number().int(), + transaction_id: z.number().int(), + }), + }, + requestBody: { + content: { + "application/json": components["schemas"]["UpdateTransaction"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["Transaction"], + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + delete_transaction: { + /** delete a transaction */ + parameters: { + path: z.object({ + group_id: z.number().int(), + transaction_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["Transaction"], + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + update_transaction_positions: { + /** update transaction positions */ + parameters: { + path: z.object({ + group_id: z.number().int(), + transaction_id: z.number().int(), + }), + }, + requestBody: { + content: { + "application/json": components["schemas"]["UpdatePositionsPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["Transaction"], + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + get_file_contents: { + /** fetch the (binary) contents of a transaction attachment */ + parameters: { + path: z.object({ + file_id: z.number().int(), + blob_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 200: z.never(), + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + preview_group: { + /** preview a group before joining using an invite token */ + requestBody: { + content: { + "application/json": components["schemas"]["PreviewGroupPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["GroupPreview"], + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + join_group: { + /** join a group using an invite token */ + requestBody: { + content: { + "application/json": components["schemas"]["PreviewGroupPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["Group"], + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + list_groups: { + /** list the current users groups */ + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": z.array(components["schemas"]["Group"]), + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + }, + }, + create_group: { + /** create a group */ + requestBody: { + content: { + "application/json": components["schemas"]["GroupPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["Group"], + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + get_group: { + /** fetch group details */ + parameters: { + path: z.object({ + group_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["Group"], + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + update_group: { + /** update group details */ + parameters: { + path: z.object({ + group_id: z.number().int(), + }), + }, + requestBody: { + content: { + "application/json": components["schemas"]["GroupPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["Group"], + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + delete_group: { + /** delete a group */ + parameters: { + path: z.object({ + group_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 204: z.never(), + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + leave_group: { + /** leave a group */ + parameters: { + path: z.object({ + group_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 204: z.never(), + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + list_members: { + /** list all members of a group */ + parameters: { + path: z.object({ group_id: z.number().int(), - type: z.literal("clearing"), - name: z.string(), - description: z.string(), - date_info: z.string(), - tags: z.array(z.string()), - clearing_shares: z.record(z.number()), - last_changed: z.string(), - deleted: z.boolean(), - }); - /** ConfirmEmailChangePayload */ - export const ConfirmEmailChangePayload = z.object({ - token: z.string(), - }); - /** ConfirmPasswordRecoveryPayload */ - export const ConfirmPasswordRecoveryPayload = z.object({ - token: z.string(), - new_password: z.string(), - }); - /** ConfirmRegistrationPayload */ - export const ConfirmRegistrationPayload = z.object({ - token: z.string(), - }); - /** CreateInvitePayload */ - export const CreateInvitePayload = z.object({ - description: z.string(), - single_use: z.boolean(), - join_as_editor: z.boolean(), - valid_until: z.string(), - }); - /** DeleteSessionPayload */ - export const DeleteSessionPayload = z.object({ - session_id: z.number().int(), - }); - /** FileAttachment */ - export const FileAttachment = z.object({ - id: z.number().int(), - filename: z.string(), - blob_id: z.union([z.number().int(), z.null()]), - mime_type: z.union([z.string(), z.null()]), - host_url: z.union([z.string(), z.null()]).optional(), - deleted: z.boolean(), - }); - /** Group */ - export const Group = z.object({ - id: z.number().int(), - name: z.string(), - description: z.string(), - currency_symbol: z.string(), - terms: z.string(), - add_user_account_on_join: z.boolean(), - created_at: z.string(), - created_by: z.number().int(), - }); - /** GroupInvite */ - export const GroupInvite = z.object({ - id: z.number().int(), - created_by: z.number().int(), - token: z.union([z.string(), z.null()]), - single_use: z.boolean(), - join_as_editor: z.boolean(), - description: z.string(), - valid_until: z.string(), - }); - /** GroupLog */ - export const GroupLog = z.object({ - id: z.number().int(), - user_id: z.number().int(), - logged_at: z.string(), - type: z.string(), - message: z.string(), - affected: z.union([z.number().int(), z.null()]), - }); - /** GroupMember */ - export const GroupMember = z.object({ - user_id: z.number().int(), - username: z.string(), - is_owner: z.boolean(), - can_write: z.boolean(), - description: z.string(), - joined_at: z.string(), - invited_by: z.union([z.number().int(), z.null()]), - }); - /** GroupMessage */ - export const GroupMessage = z.object({ - message: z.string(), - }); - /** GroupPayload */ - export const GroupPayload = z.object({ - name: z.string(), - description: z.string().optional(), - currency_symbol: z.string(), - add_user_account_on_join: z.boolean().optional(), - terms: z.string().optional(), - }); - /** GroupPreview */ - export const GroupPreview = z.object({ - id: z.number().int(), - name: z.string(), - description: z.string(), - currency_symbol: z.string(), - terms: z.string(), - created_at: z.string(), - invite_single_use: z.boolean(), - invite_valid_until: z.string(), - invite_description: z.string(), - }); - /** HTTPValidationError */ - export const HTTPValidationError = z.object({ - detail: z.array(components["schemas"]["ValidationError"]).optional(), - }); - /** LoginPayload */ - export const LoginPayload = z.object({ - username: z.string(), - password: z.string(), - session_name: z.string(), - }); - /** NewAccount */ - export const NewAccount = z.object({ - type: components["schemas"]["AccountType"], - name: z.string(), - description: z.string().optional(), - owning_user_id: z.union([z.number().int(), z.null()]).optional(), - date_info: z.union([z.string(), z.null()]).optional(), - deleted: z.boolean().optional(), - tags: z.array(z.string()).optional(), - clearing_shares: z.record(z.number()).optional(), - }); - /** NewFile */ - export const NewFile = z.object({ - filename: z.string(), - mime_type: z.string(), - content: z.string(), - }); - /** NewTransaction */ - export const NewTransaction = z.object({ - type: components["schemas"]["TransactionType"], - name: z.string(), - description: z.string(), - value: z.number(), - currency_symbol: z.string(), - currency_conversion_rate: z.number(), - billed_at: z.string(), - tags: z.array(z.string()).optional(), - creditor_shares: z.record(z.number()), - debitor_shares: z.record(z.number()), - new_files: z.array(components["schemas"]["NewFile"]).optional(), - new_positions: z.array(components["schemas"]["NewTransactionPosition"]).optional(), - }); - /** NewTransactionPosition */ - export const NewTransactionPosition = z.object({ - name: z.string(), - price: z.number(), - communist_shares: z.number(), - usages: z.record(z.number()), - }); - /** PersonalAccount */ - export const PersonalAccount = z.object({ - id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": z.array(components["schemas"]["GroupMember"]), + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + update_member_permissions: { + /** update the permissions of a group member */ + parameters: { + path: z.object({ group_id: z.number().int(), - type: z.literal("personal"), - name: z.string(), - description: z.string(), - owning_user_id: z.union([z.number().int(), z.null()]), - deleted: z.boolean(), - last_changed: z.string(), - }); - /** PreviewGroupPayload */ - export const PreviewGroupPayload = z.object({ - invite_token: z.string(), - }); - /** RecoverPasswordPayload */ - export const RecoverPasswordPayload = z.object({ - email: z.string(), - }); - /** RegisterPayload */ - export const RegisterPayload = z.object({ - username: z.string(), - password: z.string(), - email: z.string(), - invite_token: z.union([z.string(), z.null()]).optional(), - }); - /** RegisterResponse */ - export const RegisterResponse = z.object({ - user_id: z.number().int(), - }); - /** RenameSessionPayload */ - export const RenameSessionPayload = z.object({ - session_id: z.number().int(), - name: z.string(), - }); - /** Session */ - export const Session = z.object({ - id: z.number().int(), - name: z.string(), - valid_until: z.union([z.string(), z.null()]), - last_seen: z.string(), - }); - /** Token */ - export const Token = z.object({ - user_id: z.number().int(), - access_token: z.string(), - }); - /** Transaction */ - export const Transaction = z.object({ - id: z.number().int(), + }), + }, + requestBody: { + content: { + "application/json": components["schemas"]["UpdateGroupMemberPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["GroupMember"], + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + list_log: { + /** fetch the group log */ + parameters: { + path: z.object({ group_id: z.number().int(), - type: components["schemas"]["TransactionType"], - name: z.string(), - description: z.string(), - value: z.number(), - currency_symbol: z.string(), - currency_conversion_rate: z.number(), - billed_at: z.string(), - tags: z.array(z.string()), - deleted: z.boolean(), - creditor_shares: z.record(z.number()), - debitor_shares: z.record(z.number()), - last_changed: z.string(), - positions: z.array(components["schemas"]["TransactionPosition"]), - files: z.array(components["schemas"]["FileAttachment"]), - }); - /** TransactionPosition */ - export const TransactionPosition = z.object({ - name: z.string(), - price: z.number(), - communist_shares: z.number(), - usages: z.record(z.number()), - id: z.number().int(), - deleted: z.boolean(), - }); - /** - * TransactionType - * @enum {string} - */ - export const TransactionType = z.enum(["mimo", "purchase", "transfer"]); - /** UpdateFile */ - export const UpdateFile = z.object({ - id: z.number().int(), - filename: z.string(), - deleted: z.boolean(), - }); - /** UpdateGroupMemberPayload */ - export const UpdateGroupMemberPayload = z.object({ - user_id: z.number().int(), - can_write: z.boolean(), - is_owner: z.boolean(), - }); - /** UpdatePositionsPayload */ - export const UpdatePositionsPayload = z.object({ - positions: z.array(components["schemas"]["TransactionPosition"]), - }); - /** UpdateTransaction */ - export const UpdateTransaction = z.object({ - type: components["schemas"]["TransactionType"], - name: z.string(), - description: z.string(), - value: z.number(), - currency_symbol: z.string(), - currency_conversion_rate: z.number(), - billed_at: z.string(), - tags: z.array(z.string()).optional(), - creditor_shares: z.record(z.number()), - debitor_shares: z.record(z.number()), - new_files: z.array(components["schemas"]["NewFile"]).optional(), - new_positions: z.array(components["schemas"]["NewTransactionPosition"]).optional(), - changed_files: z.array(components["schemas"]["UpdateFile"]).optional(), - changed_positions: z.array(components["schemas"]["TransactionPosition"]).optional(), - }); - /** User */ - export const User = z.object({ - id: z.number().int(), - username: z.string(), - email: z.string(), - registered_at: z.string(), - deleted: z.boolean(), - pending: z.boolean(), - sessions: z.array(components["schemas"]["Session"]), - is_guest_user: z.boolean(), - }); - /** ValidationError */ - export const ValidationError = z.object({ - loc: z.array(z.union([z.string(), z.number().int()])), - msg: z.string(), - type: z.string(), - }); - /** - * VersionResponse - * @example { - * "major_version": 1, - * "minor_version": 3, - * "patch_version": 2, - * "version": "1.3.2" - * } - */ - export const VersionResponse = z.object({ - version: z.string(), - major_version: z.number().int(), - minor_version: z.number().int(), - patch_version: z.number().int(), - }); + }), + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": z.array(components["schemas"]["GroupLog"]), + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + send_group_message: { + /** post a message to the group log */ + parameters: { + path: z.object({ + group_id: z.number().int(), + }), + }, + requestBody: { + content: { + "application/json": components["schemas"]["GroupMessage"], + }, + }, + responses: { + /** @description Successful Response */ + 204: z.never(), + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + list_invites: { + /** list all invite links of a group */ + parameters: { + path: z.object({ + group_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": z.array(components["schemas"]["GroupInvite"]), + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + create_invite: { + /** create a new group invite link */ + parameters: { + path: z.object({ + group_id: z.number().int(), + }), + }, + requestBody: { + content: { + "application/json": components["schemas"]["CreateInvitePayload"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["GroupInvite"], + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + delete_invite: { + /** delete a group invite link */ + parameters: { + path: z.object({ + group_id: z.number().int(), + invite_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 204: z.never(), + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + archive_group: { + /** archive a group */ + parameters: { + path: z.object({ + group_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": z.record(z.any()), + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + unarchive_group: { + /** un-archive a group */ + parameters: { + path: z.object({ + group_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": z.record(z.any()), + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + get_token: { + /** login with username and password */ + requestBody: { + content: { + "application/x-www-form-urlencoded": components["schemas"]["Body_get_token"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["Token"], + }, + }, + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + login: { + /** login with username and password */ + requestBody: { + content: { + "application/json": components["schemas"]["LoginPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["Token"], + }, + }, + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + logout: { + /** sign out of the current session */ + responses: { + /** @description Successful Response */ + 204: z.never(), + }, + }, + register: { + /** register a new user */ + requestBody: { + content: { + "application/json": components["schemas"]["RegisterPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["RegisterResponse"], + }, + }, + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + confirm_registration: { + /** confirm a pending registration */ + requestBody: { + content: { + "application/json": components["schemas"]["ConfirmRegistrationPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 204: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + get_profile: { + /** fetch user profile information */ + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["User"], + }, + }, + }, + }, + change_password: { + /** change password */ + requestBody: { + content: { + "application/json": components["schemas"]["ChangePasswordPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 204: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + change_email: { + /** change email */ + requestBody: { + content: { + "application/json": components["schemas"]["ChangeEmailPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 204: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + confirm_email_change: { + /** confirm a pending email change */ + requestBody: { + content: { + "application/json": components["schemas"]["ConfirmEmailChangePayload"], + }, + }, + responses: { + /** @description Successful Response */ + 204: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + recover_password: { + /** recover password */ + requestBody: { + content: { + "application/json": components["schemas"]["RecoverPasswordPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 204: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + confirm_password_recovery: { + /** confirm a pending password recovery */ + requestBody: { + content: { + "application/json": components["schemas"]["ConfirmPasswordRecoveryPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 204: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + delete_session: { + /** delete a given user session */ + requestBody: { + content: { + "application/json": components["schemas"]["DeleteSessionPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 204: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + rename_session: { + /** rename a given user session */ + requestBody: { + content: { + "application/json": components["schemas"]["RenameSessionPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 204: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + list_accounts: { + /** list all accounts in a group */ + parameters: { + path: z.object({ + group_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": z.array(z.union([components["schemas"]["ClearingAccount"], components["schemas"]["PersonalAccount"]])), + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + create_account: { + /** create a new group account */ + parameters: { + path: z.object({ + group_id: z.number().int(), + }), + }, + requestBody: { + content: { + "application/json": components["schemas"]["NewAccount"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": z.union([components["schemas"]["ClearingAccount"], components["schemas"]["PersonalAccount"]]), + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + get_account: { + /** fetch a group account */ + parameters: { + path: z.object({ + group_id: z.number().int(), + account_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": z.union([components["schemas"]["ClearingAccount"], components["schemas"]["PersonalAccount"]]), + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + update_account: { + /** update an account */ + parameters: { + path: z.object({ + group_id: z.number().int(), + account_id: z.number().int(), + }), + }, + requestBody: { + content: { + "application/json": components["schemas"]["NewAccount"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": z.union([components["schemas"]["ClearingAccount"], components["schemas"]["PersonalAccount"]]), + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + delete_account: { + /** delete an account */ + parameters: { + path: z.object({ + group_id: z.number().int(), + account_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": z.union([components["schemas"]["ClearingAccount"], components["schemas"]["PersonalAccount"]]), + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + get_version: { + /** Get Version */ + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["VersionResponse"], + }, + }, + }, + }, } -export const operations = { - list_transactions: { - /** list all transactions in a group */ - parameters: { - query: z - .object({ - min_last_changed: z.union([z.string(), z.null()]).optional(), - transaction_ids: z.union([z.string(), z.null()]).optional(), - }) - .optional(), - path: z.object({ - group_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": z.array(components["schemas"]["Transaction"]), - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - create_transaction: { - /** create a new transaction */ - parameters: { - path: z.object({ - group_id: z.number().int(), - }), - }, - requestBody: { - content: { - "application/json": components["schemas"]["NewTransaction"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["Transaction"], - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - get_transaction: { - /** get transaction details */ - parameters: { - path: z.object({ - transaction_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["Transaction"], - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - update_transaction: { - /** update transaction details */ - parameters: { - path: z.object({ - transaction_id: z.number().int(), - }), - }, - requestBody: { - content: { - "application/json": components["schemas"]["UpdateTransaction"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["Transaction"], - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - delete_transaction: { - /** delete a transaction */ - parameters: { - path: z.object({ - transaction_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["Transaction"], - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - update_transaction_positions: { - /** update transaction positions */ - parameters: { - path: z.object({ - transaction_id: z.number().int(), - }), - }, - requestBody: { - content: { - "application/json": components["schemas"]["UpdatePositionsPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["Transaction"], - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - get_file_contents: { - /** fetch the (binary) contents of a transaction attachment */ - parameters: { - path: z.object({ - file_id: z.number().int(), - blob_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 200: z.never(), - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - preview_group: { - /** preview a group before joining using an invite token */ - requestBody: { - content: { - "application/json": components["schemas"]["PreviewGroupPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["GroupPreview"], - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - join_group: { - /** join a group using an invite token */ - requestBody: { - content: { - "application/json": components["schemas"]["PreviewGroupPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["Group"], - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - list_groups: { - /** list the current users groups */ - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": z.array(components["schemas"]["Group"]), - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - }, - }, - create_group: { - /** create a group */ - requestBody: { - content: { - "application/json": components["schemas"]["GroupPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["Group"], - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - get_group: { - /** fetch group details */ - parameters: { - path: z.object({ - group_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["Group"], - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - update_group: { - /** update group details */ - parameters: { - path: z.object({ - group_id: z.number().int(), - }), - }, - requestBody: { - content: { - "application/json": components["schemas"]["GroupPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["Group"], - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - delete_group: { - /** delete a group */ - parameters: { - path: z.object({ - group_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 204: z.never(), - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - leave_group: { - /** leave a group */ - parameters: { - path: z.object({ - group_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 204: z.never(), - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - list_members: { - /** list all members of a group */ - parameters: { - path: z.object({ - group_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": z.array(components["schemas"]["GroupMember"]), - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - update_member_permissions: { - /** update the permissions of a group member */ - parameters: { - path: z.object({ - group_id: z.number().int(), - }), - }, - requestBody: { - content: { - "application/json": components["schemas"]["UpdateGroupMemberPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["GroupMember"], - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - list_log: { - /** fetch the group log */ - parameters: { - path: z.object({ - group_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": z.array(components["schemas"]["GroupLog"]), - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - send_group_message: { - /** post a message to the group log */ - parameters: { - path: z.object({ - group_id: z.number().int(), - }), - }, - requestBody: { - content: { - "application/json": components["schemas"]["GroupMessage"], - }, - }, - responses: { - /** @description Successful Response */ - 204: z.never(), - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - list_invites: { - /** list all invite links of a group */ - parameters: { - path: z.object({ - group_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": z.array(components["schemas"]["GroupInvite"]), - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - create_invite: { - /** create a new group invite link */ - parameters: { - path: z.object({ - group_id: z.number().int(), - }), - }, - requestBody: { - content: { - "application/json": components["schemas"]["CreateInvitePayload"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["GroupInvite"], - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - delete_invite: { - /** delete a group invite link */ - parameters: { - path: z.object({ - group_id: z.number().int(), - invite_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 204: z.never(), - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - get_token: { - /** login with username and password */ - requestBody: { - content: { - "application/x-www-form-urlencoded": components["schemas"]["Body_get_token"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["Token"], - }, - }, - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - login: { - /** login with username and password */ - requestBody: { - content: { - "application/json": components["schemas"]["LoginPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["Token"], - }, - }, - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - logout: { - /** sign out of the current session */ - responses: { - /** @description Successful Response */ - 204: z.never(), - }, - }, - register: { - /** register a new user */ - requestBody: { - content: { - "application/json": components["schemas"]["RegisterPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["RegisterResponse"], - }, - }, - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - confirm_registration: { - /** confirm a pending registration */ - requestBody: { - content: { - "application/json": components["schemas"]["ConfirmRegistrationPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 204: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - get_profile: { - /** fetch user profile information */ - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["User"], - }, - }, - }, - }, - change_password: { - /** change password */ - requestBody: { - content: { - "application/json": components["schemas"]["ChangePasswordPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 204: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - change_email: { - /** change email */ - requestBody: { - content: { - "application/json": components["schemas"]["ChangeEmailPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 204: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - confirm_email_change: { - /** confirm a pending email change */ - requestBody: { - content: { - "application/json": components["schemas"]["ConfirmEmailChangePayload"], - }, - }, - responses: { - /** @description Successful Response */ - 204: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - recover_password: { - /** recover password */ - requestBody: { - content: { - "application/json": components["schemas"]["RecoverPasswordPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 204: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - confirm_password_recovery: { - /** confirm a pending password recovery */ - requestBody: { - content: { - "application/json": components["schemas"]["ConfirmPasswordRecoveryPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 204: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - delete_session: { - /** delete a given user session */ - requestBody: { - content: { - "application/json": components["schemas"]["DeleteSessionPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 204: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - rename_session: { - /** rename a given user session */ - requestBody: { - content: { - "application/json": components["schemas"]["RenameSessionPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 204: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - list_accounts: { - /** list all accounts in a group */ - parameters: { - path: z.object({ - group_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": z.array( - z.union([components["schemas"]["ClearingAccount"], components["schemas"]["PersonalAccount"]]) - ), - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - create_account: { - /** create a new group account */ - parameters: { - path: z.object({ - group_id: z.number().int(), - }), - }, - requestBody: { - content: { - "application/json": components["schemas"]["NewAccount"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": z.union([ - components["schemas"]["ClearingAccount"], - components["schemas"]["PersonalAccount"], - ]), - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - get_account: { - /** fetch a group account */ - parameters: { - path: z.object({ - account_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": z.union([ - components["schemas"]["ClearingAccount"], - components["schemas"]["PersonalAccount"], - ]), - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - update_account: { - /** update an account */ - parameters: { - path: z.object({ - account_id: z.number().int(), - }), - }, - requestBody: { - content: { - "application/json": components["schemas"]["NewAccount"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": z.union([ - components["schemas"]["ClearingAccount"], - components["schemas"]["PersonalAccount"], - ]), - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - delete_account: { - /** delete an account */ - parameters: { - path: z.object({ - account_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": z.union([ - components["schemas"]["ClearingAccount"], - components["schemas"]["PersonalAccount"], - ]), - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - get_version: { - /** Get Version */ - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["VersionResponse"], - }, - }, - }, - }, -}; - export const paths = { - "/api/v1/groups/{group_id}/transactions": { - /** list all transactions in a group */ - get: operations["list_transactions"], - /** create a new transaction */ - post: operations["create_transaction"], - }, - "/api/v1/transactions/{transaction_id}": { - /** get transaction details */ - get: operations["get_transaction"], - /** update transaction details */ - post: operations["update_transaction"], - /** delete a transaction */ - delete: operations["delete_transaction"], - }, - "/api/v1/transactions/{transaction_id}/positions": { - /** update transaction positions */ - post: operations["update_transaction_positions"], - }, - "/api/v1/files/{file_id}/{blob_id}": { - /** fetch the (binary) contents of a transaction attachment */ - get: operations["get_file_contents"], - }, - "/api/v1/groups/preview": { - /** preview a group before joining using an invite token */ - post: operations["preview_group"], - }, - "/api/v1/groups/join": { - /** join a group using an invite token */ - post: operations["join_group"], - }, - "/api/v1/groups": { - /** list the current users groups */ - get: operations["list_groups"], - /** create a group */ - post: operations["create_group"], - }, - "/api/v1/groups/{group_id}": { - /** fetch group details */ - get: operations["get_group"], - /** update group details */ - post: operations["update_group"], - /** delete a group */ - delete: operations["delete_group"], - }, - "/api/v1/groups/{group_id}/leave": { - /** leave a group */ - post: operations["leave_group"], - }, - "/api/v1/groups/{group_id}/members": { - /** list all members of a group */ - get: operations["list_members"], - /** update the permissions of a group member */ - post: operations["update_member_permissions"], - }, - "/api/v1/groups/{group_id}/logs": { - /** fetch the group log */ - get: operations["list_log"], - }, - "/api/v1/groups/{group_id}/send_message": { - /** post a message to the group log */ - post: operations["send_group_message"], - }, - "/api/v1/groups/{group_id}/invites": { - /** list all invite links of a group */ - get: operations["list_invites"], - /** create a new group invite link */ - post: operations["create_invite"], - }, - "/api/v1/groups/{group_id}/invites/{invite_id}": { - /** delete a group invite link */ - delete: operations["delete_invite"], - }, - "/api/v1/auth/token": { - /** login with username and password */ - post: operations["get_token"], - }, - "/api/v1/auth/login": { - /** login with username and password */ - post: operations["login"], - }, - "/api/v1/auth/logout": { - /** sign out of the current session */ - post: operations["logout"], - }, - "/api/v1/auth/register": { - /** register a new user */ - post: operations["register"], - }, - "/api/v1/auth/confirm_registration": { - /** confirm a pending registration */ - post: operations["confirm_registration"], - }, - "/api/v1/profile": { - /** fetch user profile information */ - get: operations["get_profile"], - }, - "/api/v1/profile/change_password": { - /** change password */ - post: operations["change_password"], - }, - "/api/v1/profile/change_email": { - /** change email */ - post: operations["change_email"], - }, - "/api/v1/auth/confirm_email_change": { - /** confirm a pending email change */ - post: operations["confirm_email_change"], - }, - "/api/v1/auth/recover_password": { - /** recover password */ - post: operations["recover_password"], - }, - "/api/v1/auth/confirm_password_recovery": { - /** confirm a pending password recovery */ - post: operations["confirm_password_recovery"], - }, - "/api/v1/auth/delete_session": { - /** delete a given user session */ - post: operations["delete_session"], - }, - "/api/v1/auth/rename_session": { - /** rename a given user session */ - post: operations["rename_session"], - }, - "/api/v1/groups/{group_id}/accounts": { - /** list all accounts in a group */ - get: operations["list_accounts"], - /** create a new group account */ - post: operations["create_account"], - }, - "/api/v1/accounts/{account_id}": { - /** fetch a group account */ - get: operations["get_account"], - /** update an account */ - post: operations["update_account"], - /** delete an account */ - delete: operations["delete_account"], - }, - "/api/version": { - /** Get Version */ - get: operations["get_version"], - }, -}; + "/api/v1/groups/{group_id}/transactions": { + /** list all transactions in a group */ + get: operations["list_transactions"], + /** create a new transaction */ + post: operations["create_transaction"], + }, + "/api/v1/groups/{group_id}/transactions/{transaction_id}": { + /** get transaction details */ + get: operations["get_transaction"], + /** update transaction details */ + post: operations["update_transaction"], + /** delete a transaction */ + delete: operations["delete_transaction"], + }, + "/api/v1/groups/{group_id}/transactions/{transaction_id}/positions": { + /** update transaction positions */ + post: operations["update_transaction_positions"], + }, + "/api/v1/files/{file_id}/{blob_id}": { + /** fetch the (binary) contents of a transaction attachment */ + get: operations["get_file_contents"], + }, + "/api/v1/groups/preview": { + /** preview a group before joining using an invite token */ + post: operations["preview_group"], + }, + "/api/v1/groups/join": { + /** join a group using an invite token */ + post: operations["join_group"], + }, + "/api/v1/groups": { + /** list the current users groups */ + get: operations["list_groups"], + /** create a group */ + post: operations["create_group"], + }, + "/api/v1/groups/{group_id}": { + /** fetch group details */ + get: operations["get_group"], + /** update group details */ + post: operations["update_group"], + /** delete a group */ + delete: operations["delete_group"], + }, + "/api/v1/groups/{group_id}/leave": { + /** leave a group */ + post: operations["leave_group"], + }, + "/api/v1/groups/{group_id}/members": { + /** list all members of a group */ + get: operations["list_members"], + /** update the permissions of a group member */ + post: operations["update_member_permissions"], + }, + "/api/v1/groups/{group_id}/logs": { + /** fetch the group log */ + get: operations["list_log"], + }, + "/api/v1/groups/{group_id}/send_message": { + /** post a message to the group log */ + post: operations["send_group_message"], + }, + "/api/v1/groups/{group_id}/invites": { + /** list all invite links of a group */ + get: operations["list_invites"], + /** create a new group invite link */ + post: operations["create_invite"], + }, + "/api/v1/groups/{group_id}/invites/{invite_id}": { + /** delete a group invite link */ + delete: operations["delete_invite"], + }, + "/api/v1/groups/{group_id}/archive": { + /** archive a group */ + post: operations["archive_group"], + }, + "/api/v1/groups/{group_id}/un-archive": { + /** un-archive a group */ + post: operations["unarchive_group"], + }, + "/api/v1/auth/token": { + /** login with username and password */ + post: operations["get_token"], + }, + "/api/v1/auth/login": { + /** login with username and password */ + post: operations["login"], + }, + "/api/v1/auth/logout": { + /** sign out of the current session */ + post: operations["logout"], + }, + "/api/v1/auth/register": { + /** register a new user */ + post: operations["register"], + }, + "/api/v1/auth/confirm_registration": { + /** confirm a pending registration */ + post: operations["confirm_registration"], + }, + "/api/v1/profile": { + /** fetch user profile information */ + get: operations["get_profile"], + }, + "/api/v1/profile/change_password": { + /** change password */ + post: operations["change_password"], + }, + "/api/v1/profile/change_email": { + /** change email */ + post: operations["change_email"], + }, + "/api/v1/auth/confirm_email_change": { + /** confirm a pending email change */ + post: operations["confirm_email_change"], + }, + "/api/v1/auth/recover_password": { + /** recover password */ + post: operations["recover_password"], + }, + "/api/v1/auth/confirm_password_recovery": { + /** confirm a pending password recovery */ + post: operations["confirm_password_recovery"], + }, + "/api/v1/auth/delete_session": { + /** delete a given user session */ + post: operations["delete_session"], + }, + "/api/v1/auth/rename_session": { + /** rename a given user session */ + post: operations["rename_session"], + }, + "/api/v1/groups/{group_id}/accounts": { + /** list all accounts in a group */ + get: operations["list_accounts"], + /** create a new group account */ + post: operations["create_account"], + }, + "/api/v1/groups/{group_id}/accounts/{account_id}": { + /** fetch a group account */ + get: operations["get_account"], + /** update an account */ + post: operations["update_account"], + /** delete an account */ + delete: operations["delete_account"], + }, + "/api/version": { + /** Get Version */ + get: operations["get_version"], + }, +} diff --git a/frontend/libs/api/src/lib/generated/services/AccountsService.ts b/frontend/libs/api/src/lib/generated/services/AccountsService.ts index d4f37d0..6e5c103 100644 --- a/frontend/libs/api/src/lib/generated/services/AccountsService.ts +++ b/frontend/libs/api/src/lib/generated/services/AccountsService.ts @@ -1,28 +1,29 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { ClearingAccount } from "../models/ClearingAccount"; -import type { NewAccount } from "../models/NewAccount"; -import type { PersonalAccount } from "../models/PersonalAccount"; - -import type { CancelablePromise } from "../core/CancelablePromise"; -import type { BaseHttpRequest } from "../core/BaseHttpRequest"; - +import type { ClearingAccount } from '../models/ClearingAccount'; +import type { NewAccount } from '../models/NewAccount'; +import type { PersonalAccount } from '../models/PersonalAccount'; +import type { CancelablePromise } from '../core/CancelablePromise'; +import type { BaseHttpRequest } from '../core/BaseHttpRequest'; export class AccountsService { constructor(public readonly httpRequest: BaseHttpRequest) {} - /** * list all accounts in a group * @returns any Successful Response * @throws ApiError */ - public listAccounts({ groupId }: { groupId: number }): CancelablePromise> { + public listAccounts({ + groupId, + }: { + groupId: number, + }): CancelablePromise> { return this.httpRequest.request({ - method: "GET", - url: "/api/v1/groups/{group_id}/accounts", + method: 'GET', + url: '/api/v1/groups/{group_id}/accounts', path: { - group_id: groupId, + 'group_id': groupId, }, errors: { 401: `unauthorized`, @@ -32,7 +33,6 @@ export class AccountsService { }, }); } - /** * create a new group account * @returns any Successful Response @@ -42,17 +42,17 @@ export class AccountsService { groupId, requestBody, }: { - groupId: number; - requestBody: NewAccount; - }): CancelablePromise { + groupId: number, + requestBody: NewAccount, + }): CancelablePromise<(ClearingAccount | PersonalAccount)> { return this.httpRequest.request({ - method: "POST", - url: "/api/v1/groups/{group_id}/accounts", + method: 'POST', + url: '/api/v1/groups/{group_id}/accounts', path: { - group_id: groupId, + 'group_id': groupId, }, body: requestBody, - mediaType: "application/json", + mediaType: 'application/json', errors: { 401: `unauthorized`, 403: `forbidden`, @@ -61,18 +61,24 @@ export class AccountsService { }, }); } - /** * fetch a group account * @returns any Successful Response * @throws ApiError */ - public getAccount({ accountId }: { accountId: number }): CancelablePromise { + public getAccount({ + groupId, + accountId, + }: { + groupId: number, + accountId: number, + }): CancelablePromise<(ClearingAccount | PersonalAccount)> { return this.httpRequest.request({ - method: "GET", - url: "/api/v1/accounts/{account_id}", + method: 'GET', + url: '/api/v1/groups/{group_id}/accounts/{account_id}', path: { - account_id: accountId, + 'group_id': groupId, + 'account_id': accountId, }, errors: { 401: `unauthorized`, @@ -82,27 +88,29 @@ export class AccountsService { }, }); } - /** * update an account * @returns any Successful Response * @throws ApiError */ public updateAccount({ + groupId, accountId, requestBody, }: { - accountId: number; - requestBody: NewAccount; - }): CancelablePromise { + groupId: number, + accountId: number, + requestBody: NewAccount, + }): CancelablePromise<(ClearingAccount | PersonalAccount)> { return this.httpRequest.request({ - method: "POST", - url: "/api/v1/accounts/{account_id}", + method: 'POST', + url: '/api/v1/groups/{group_id}/accounts/{account_id}', path: { - account_id: accountId, + 'group_id': groupId, + 'account_id': accountId, }, body: requestBody, - mediaType: "application/json", + mediaType: 'application/json', errors: { 401: `unauthorized`, 403: `forbidden`, @@ -111,18 +119,24 @@ export class AccountsService { }, }); } - /** * delete an account * @returns any Successful Response * @throws ApiError */ - public deleteAccount({ accountId }: { accountId: number }): CancelablePromise { + public deleteAccount({ + groupId, + accountId, + }: { + groupId: number, + accountId: number, + }): CancelablePromise<(ClearingAccount | PersonalAccount)> { return this.httpRequest.request({ - method: "DELETE", - url: "/api/v1/accounts/{account_id}", + method: 'DELETE', + url: '/api/v1/groups/{group_id}/accounts/{account_id}', path: { - account_id: accountId, + 'group_id': groupId, + 'account_id': accountId, }, errors: { 401: `unauthorized`, diff --git a/frontend/libs/api/src/lib/generated/services/AuthService.ts b/frontend/libs/api/src/lib/generated/services/AuthService.ts index 59a79c6..d431750 100644 --- a/frontend/libs/api/src/lib/generated/services/AuthService.ts +++ b/frontend/libs/api/src/lib/generated/services/AuthService.ts @@ -1,62 +1,65 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { Body_get_token } from "../models/Body_get_token"; -import type { ChangeEmailPayload } from "../models/ChangeEmailPayload"; -import type { ChangePasswordPayload } from "../models/ChangePasswordPayload"; -import type { ConfirmEmailChangePayload } from "../models/ConfirmEmailChangePayload"; -import type { ConfirmPasswordRecoveryPayload } from "../models/ConfirmPasswordRecoveryPayload"; -import type { ConfirmRegistrationPayload } from "../models/ConfirmRegistrationPayload"; -import type { DeleteSessionPayload } from "../models/DeleteSessionPayload"; -import type { LoginPayload } from "../models/LoginPayload"; -import type { RecoverPasswordPayload } from "../models/RecoverPasswordPayload"; -import type { RegisterPayload } from "../models/RegisterPayload"; -import type { RegisterResponse } from "../models/RegisterResponse"; -import type { RenameSessionPayload } from "../models/RenameSessionPayload"; -import type { Token } from "../models/Token"; -import type { User } from "../models/User"; - -import type { CancelablePromise } from "../core/CancelablePromise"; -import type { BaseHttpRequest } from "../core/BaseHttpRequest"; - +import type { Body_get_token } from '../models/Body_get_token'; +import type { ChangeEmailPayload } from '../models/ChangeEmailPayload'; +import type { ChangePasswordPayload } from '../models/ChangePasswordPayload'; +import type { ConfirmEmailChangePayload } from '../models/ConfirmEmailChangePayload'; +import type { ConfirmPasswordRecoveryPayload } from '../models/ConfirmPasswordRecoveryPayload'; +import type { ConfirmRegistrationPayload } from '../models/ConfirmRegistrationPayload'; +import type { DeleteSessionPayload } from '../models/DeleteSessionPayload'; +import type { LoginPayload } from '../models/LoginPayload'; +import type { RecoverPasswordPayload } from '../models/RecoverPasswordPayload'; +import type { RegisterPayload } from '../models/RegisterPayload'; +import type { RegisterResponse } from '../models/RegisterResponse'; +import type { RenameSessionPayload } from '../models/RenameSessionPayload'; +import type { Token } from '../models/Token'; +import type { User } from '../models/User'; +import type { CancelablePromise } from '../core/CancelablePromise'; +import type { BaseHttpRequest } from '../core/BaseHttpRequest'; export class AuthService { constructor(public readonly httpRequest: BaseHttpRequest) {} - /** * login with username and password * @returns Token Successful Response * @throws ApiError */ - public getToken({ formData }: { formData: Body_get_token }): CancelablePromise { + public getToken({ + formData, + }: { + formData: Body_get_token, + }): CancelablePromise { return this.httpRequest.request({ - method: "POST", - url: "/api/v1/auth/token", + method: 'POST', + url: '/api/v1/auth/token', formData: formData, - mediaType: "application/x-www-form-urlencoded", + mediaType: 'application/x-www-form-urlencoded', errors: { 422: `Validation Error`, }, }); } - /** * login with username and password * @returns Token Successful Response * @throws ApiError */ - public login({ requestBody }: { requestBody: LoginPayload }): CancelablePromise { + public login({ + requestBody, + }: { + requestBody: LoginPayload, + }): CancelablePromise { return this.httpRequest.request({ - method: "POST", - url: "/api/v1/auth/login", + method: 'POST', + url: '/api/v1/auth/login', body: requestBody, - mediaType: "application/json", + mediaType: 'application/json', errors: { 422: `Validation Error`, }, }); } - /** * sign out of the current session * @returns void @@ -64,45 +67,50 @@ export class AuthService { */ public logout(): CancelablePromise { return this.httpRequest.request({ - method: "POST", - url: "/api/v1/auth/logout", + method: 'POST', + url: '/api/v1/auth/logout', }); } - /** * register a new user * @returns RegisterResponse Successful Response * @throws ApiError */ - public register({ requestBody }: { requestBody: RegisterPayload }): CancelablePromise { + public register({ + requestBody, + }: { + requestBody: RegisterPayload, + }): CancelablePromise { return this.httpRequest.request({ - method: "POST", - url: "/api/v1/auth/register", + method: 'POST', + url: '/api/v1/auth/register', body: requestBody, - mediaType: "application/json", + mediaType: 'application/json', errors: { 422: `Validation Error`, }, }); } - /** * confirm a pending registration * @returns void * @throws ApiError */ - public confirmRegistration({ requestBody }: { requestBody: ConfirmRegistrationPayload }): CancelablePromise { + public confirmRegistration({ + requestBody, + }: { + requestBody: ConfirmRegistrationPayload, + }): CancelablePromise { return this.httpRequest.request({ - method: "POST", - url: "/api/v1/auth/confirm_registration", + method: 'POST', + url: '/api/v1/auth/confirm_registration', body: requestBody, - mediaType: "application/json", + mediaType: 'application/json', errors: { 422: `Validation Error`, }, }); } - /** * fetch user profile information * @returns User Successful Response @@ -110,79 +118,90 @@ export class AuthService { */ public getProfile(): CancelablePromise { return this.httpRequest.request({ - method: "GET", - url: "/api/v1/profile", + method: 'GET', + url: '/api/v1/profile', }); } - /** * change password * @returns void * @throws ApiError */ - public changePassword({ requestBody }: { requestBody: ChangePasswordPayload }): CancelablePromise { + public changePassword({ + requestBody, + }: { + requestBody: ChangePasswordPayload, + }): CancelablePromise { return this.httpRequest.request({ - method: "POST", - url: "/api/v1/profile/change_password", + method: 'POST', + url: '/api/v1/profile/change_password', body: requestBody, - mediaType: "application/json", + mediaType: 'application/json', errors: { 422: `Validation Error`, }, }); } - /** * change email * @returns void * @throws ApiError */ - public changeEmail({ requestBody }: { requestBody: ChangeEmailPayload }): CancelablePromise { + public changeEmail({ + requestBody, + }: { + requestBody: ChangeEmailPayload, + }): CancelablePromise { return this.httpRequest.request({ - method: "POST", - url: "/api/v1/profile/change_email", + method: 'POST', + url: '/api/v1/profile/change_email', body: requestBody, - mediaType: "application/json", + mediaType: 'application/json', errors: { 422: `Validation Error`, }, }); } - /** * confirm a pending email change * @returns void * @throws ApiError */ - public confirmEmailChange({ requestBody }: { requestBody: ConfirmEmailChangePayload }): CancelablePromise { + public confirmEmailChange({ + requestBody, + }: { + requestBody: ConfirmEmailChangePayload, + }): CancelablePromise { return this.httpRequest.request({ - method: "POST", - url: "/api/v1/auth/confirm_email_change", + method: 'POST', + url: '/api/v1/auth/confirm_email_change', body: requestBody, - mediaType: "application/json", + mediaType: 'application/json', errors: { 422: `Validation Error`, }, }); } - /** * recover password * @returns void * @throws ApiError */ - public recoverPassword({ requestBody }: { requestBody: RecoverPasswordPayload }): CancelablePromise { + public recoverPassword({ + requestBody, + }: { + requestBody: RecoverPasswordPayload, + }): CancelablePromise { return this.httpRequest.request({ - method: "POST", - url: "/api/v1/auth/recover_password", + method: 'POST', + url: '/api/v1/auth/recover_password', body: requestBody, - mediaType: "application/json", + mediaType: 'application/json', errors: { 422: `Validation Error`, }, }); } - /** * confirm a pending password recovery * @returns void @@ -191,47 +210,53 @@ export class AuthService { public confirmPasswordRecovery({ requestBody, }: { - requestBody: ConfirmPasswordRecoveryPayload; + requestBody: ConfirmPasswordRecoveryPayload, }): CancelablePromise { return this.httpRequest.request({ - method: "POST", - url: "/api/v1/auth/confirm_password_recovery", + method: 'POST', + url: '/api/v1/auth/confirm_password_recovery', body: requestBody, - mediaType: "application/json", + mediaType: 'application/json', errors: { 422: `Validation Error`, }, }); } - /** * delete a given user session * @returns void * @throws ApiError */ - public deleteSession({ requestBody }: { requestBody: DeleteSessionPayload }): CancelablePromise { + public deleteSession({ + requestBody, + }: { + requestBody: DeleteSessionPayload, + }): CancelablePromise { return this.httpRequest.request({ - method: "POST", - url: "/api/v1/auth/delete_session", + method: 'POST', + url: '/api/v1/auth/delete_session', body: requestBody, - mediaType: "application/json", + mediaType: 'application/json', errors: { 422: `Validation Error`, }, }); } - /** * rename a given user session * @returns void * @throws ApiError */ - public renameSession({ requestBody }: { requestBody: RenameSessionPayload }): CancelablePromise { + public renameSession({ + requestBody, + }: { + requestBody: RenameSessionPayload, + }): CancelablePromise { return this.httpRequest.request({ - method: "POST", - url: "/api/v1/auth/rename_session", + method: 'POST', + url: '/api/v1/auth/rename_session', body: requestBody, - mediaType: "application/json", + mediaType: 'application/json', errors: { 422: `Validation Error`, }, diff --git a/frontend/libs/api/src/lib/generated/services/CommonService.ts b/frontend/libs/api/src/lib/generated/services/CommonService.ts index 9a11787..4f6588f 100644 --- a/frontend/libs/api/src/lib/generated/services/CommonService.ts +++ b/frontend/libs/api/src/lib/generated/services/CommonService.ts @@ -1,15 +1,12 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { VersionResponse } from "../models/VersionResponse"; - -import type { CancelablePromise } from "../core/CancelablePromise"; -import type { BaseHttpRequest } from "../core/BaseHttpRequest"; - +import type { VersionResponse } from '../models/VersionResponse'; +import type { CancelablePromise } from '../core/CancelablePromise'; +import type { BaseHttpRequest } from '../core/BaseHttpRequest'; export class CommonService { constructor(public readonly httpRequest: BaseHttpRequest) {} - /** * Get Version * @returns VersionResponse Successful Response @@ -17,8 +14,8 @@ export class CommonService { */ public getVersion(): CancelablePromise { return this.httpRequest.request({ - method: "GET", - url: "/api/version", + method: 'GET', + url: '/api/version', }); } } diff --git a/frontend/libs/api/src/lib/generated/services/GroupsService.ts b/frontend/libs/api/src/lib/generated/services/GroupsService.ts index a24f243..ddf3e5c 100644 --- a/frontend/libs/api/src/lib/generated/services/GroupsService.ts +++ b/frontend/libs/api/src/lib/generated/services/GroupsService.ts @@ -1,35 +1,36 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { CreateInvitePayload } from "../models/CreateInvitePayload"; -import type { Group } from "../models/Group"; -import type { GroupInvite } from "../models/GroupInvite"; -import type { GroupLog } from "../models/GroupLog"; -import type { GroupMember } from "../models/GroupMember"; -import type { GroupMessage } from "../models/GroupMessage"; -import type { GroupPayload } from "../models/GroupPayload"; -import type { GroupPreview } from "../models/GroupPreview"; -import type { PreviewGroupPayload } from "../models/PreviewGroupPayload"; -import type { UpdateGroupMemberPayload } from "../models/UpdateGroupMemberPayload"; - -import type { CancelablePromise } from "../core/CancelablePromise"; -import type { BaseHttpRequest } from "../core/BaseHttpRequest"; - +import type { CreateInvitePayload } from '../models/CreateInvitePayload'; +import type { Group } from '../models/Group'; +import type { GroupInvite } from '../models/GroupInvite'; +import type { GroupLog } from '../models/GroupLog'; +import type { GroupMember } from '../models/GroupMember'; +import type { GroupMessage } from '../models/GroupMessage'; +import type { GroupPayload } from '../models/GroupPayload'; +import type { GroupPreview } from '../models/GroupPreview'; +import type { PreviewGroupPayload } from '../models/PreviewGroupPayload'; +import type { UpdateGroupMemberPayload } from '../models/UpdateGroupMemberPayload'; +import type { CancelablePromise } from '../core/CancelablePromise'; +import type { BaseHttpRequest } from '../core/BaseHttpRequest'; export class GroupsService { constructor(public readonly httpRequest: BaseHttpRequest) {} - /** * preview a group before joining using an invite token * @returns GroupPreview Successful Response * @throws ApiError */ - public previewGroup({ requestBody }: { requestBody: PreviewGroupPayload }): CancelablePromise { + public previewGroup({ + requestBody, + }: { + requestBody: PreviewGroupPayload, + }): CancelablePromise { return this.httpRequest.request({ - method: "POST", - url: "/api/v1/groups/preview", + method: 'POST', + url: '/api/v1/groups/preview', body: requestBody, - mediaType: "application/json", + mediaType: 'application/json', errors: { 401: `unauthorized`, 403: `forbidden`, @@ -38,18 +39,21 @@ export class GroupsService { }, }); } - /** * join a group using an invite token * @returns Group Successful Response * @throws ApiError */ - public joinGroup({ requestBody }: { requestBody: PreviewGroupPayload }): CancelablePromise { + public joinGroup({ + requestBody, + }: { + requestBody: PreviewGroupPayload, + }): CancelablePromise { return this.httpRequest.request({ - method: "POST", - url: "/api/v1/groups/join", + method: 'POST', + url: '/api/v1/groups/join', body: requestBody, - mediaType: "application/json", + mediaType: 'application/json', errors: { 401: `unauthorized`, 403: `forbidden`, @@ -58,7 +62,6 @@ export class GroupsService { }, }); } - /** * list the current users groups * @returns Group Successful Response @@ -66,8 +69,8 @@ export class GroupsService { */ public listGroups(): CancelablePromise> { return this.httpRequest.request({ - method: "GET", - url: "/api/v1/groups", + method: 'GET', + url: '/api/v1/groups', errors: { 401: `unauthorized`, 403: `forbidden`, @@ -75,18 +78,21 @@ export class GroupsService { }, }); } - /** * create a group * @returns Group Successful Response * @throws ApiError */ - public createGroup({ requestBody }: { requestBody: GroupPayload }): CancelablePromise { + public createGroup({ + requestBody, + }: { + requestBody: GroupPayload, + }): CancelablePromise { return this.httpRequest.request({ - method: "POST", - url: "/api/v1/groups", + method: 'POST', + url: '/api/v1/groups', body: requestBody, - mediaType: "application/json", + mediaType: 'application/json', errors: { 401: `unauthorized`, 403: `forbidden`, @@ -95,18 +101,21 @@ export class GroupsService { }, }); } - /** * fetch group details * @returns Group Successful Response * @throws ApiError */ - public getGroup({ groupId }: { groupId: number }): CancelablePromise { + public getGroup({ + groupId, + }: { + groupId: number, + }): CancelablePromise { return this.httpRequest.request({ - method: "GET", - url: "/api/v1/groups/{group_id}", + method: 'GET', + url: '/api/v1/groups/{group_id}', path: { - group_id: groupId, + 'group_id': groupId, }, errors: { 401: `unauthorized`, @@ -116,7 +125,6 @@ export class GroupsService { }, }); } - /** * update group details * @returns Group Successful Response @@ -126,17 +134,17 @@ export class GroupsService { groupId, requestBody, }: { - groupId: number; - requestBody: GroupPayload; + groupId: number, + requestBody: GroupPayload, }): CancelablePromise { return this.httpRequest.request({ - method: "POST", - url: "/api/v1/groups/{group_id}", + method: 'POST', + url: '/api/v1/groups/{group_id}', path: { - group_id: groupId, + 'group_id': groupId, }, body: requestBody, - mediaType: "application/json", + mediaType: 'application/json', errors: { 401: `unauthorized`, 403: `forbidden`, @@ -145,18 +153,21 @@ export class GroupsService { }, }); } - /** * delete a group * @returns void * @throws ApiError */ - public deleteGroup({ groupId }: { groupId: number }): CancelablePromise { + public deleteGroup({ + groupId, + }: { + groupId: number, + }): CancelablePromise { return this.httpRequest.request({ - method: "DELETE", - url: "/api/v1/groups/{group_id}", + method: 'DELETE', + url: '/api/v1/groups/{group_id}', path: { - group_id: groupId, + 'group_id': groupId, }, errors: { 401: `unauthorized`, @@ -166,18 +177,21 @@ export class GroupsService { }, }); } - /** * leave a group * @returns void * @throws ApiError */ - public leaveGroup({ groupId }: { groupId: number }): CancelablePromise { + public leaveGroup({ + groupId, + }: { + groupId: number, + }): CancelablePromise { return this.httpRequest.request({ - method: "POST", - url: "/api/v1/groups/{group_id}/leave", + method: 'POST', + url: '/api/v1/groups/{group_id}/leave', path: { - group_id: groupId, + 'group_id': groupId, }, errors: { 401: `unauthorized`, @@ -187,18 +201,21 @@ export class GroupsService { }, }); } - /** * list all members of a group * @returns GroupMember Successful Response * @throws ApiError */ - public listMembers({ groupId }: { groupId: number }): CancelablePromise> { + public listMembers({ + groupId, + }: { + groupId: number, + }): CancelablePromise> { return this.httpRequest.request({ - method: "GET", - url: "/api/v1/groups/{group_id}/members", + method: 'GET', + url: '/api/v1/groups/{group_id}/members', path: { - group_id: groupId, + 'group_id': groupId, }, errors: { 401: `unauthorized`, @@ -208,7 +225,6 @@ export class GroupsService { }, }); } - /** * update the permissions of a group member * @returns GroupMember Successful Response @@ -218,17 +234,17 @@ export class GroupsService { groupId, requestBody, }: { - groupId: number; - requestBody: UpdateGroupMemberPayload; + groupId: number, + requestBody: UpdateGroupMemberPayload, }): CancelablePromise { return this.httpRequest.request({ - method: "POST", - url: "/api/v1/groups/{group_id}/members", + method: 'POST', + url: '/api/v1/groups/{group_id}/members', path: { - group_id: groupId, + 'group_id': groupId, }, body: requestBody, - mediaType: "application/json", + mediaType: 'application/json', errors: { 401: `unauthorized`, 403: `forbidden`, @@ -237,18 +253,21 @@ export class GroupsService { }, }); } - /** * fetch the group log * @returns GroupLog Successful Response * @throws ApiError */ - public listLog({ groupId }: { groupId: number }): CancelablePromise> { + public listLog({ + groupId, + }: { + groupId: number, + }): CancelablePromise> { return this.httpRequest.request({ - method: "GET", - url: "/api/v1/groups/{group_id}/logs", + method: 'GET', + url: '/api/v1/groups/{group_id}/logs', path: { - group_id: groupId, + 'group_id': groupId, }, errors: { 401: `unauthorized`, @@ -258,7 +277,6 @@ export class GroupsService { }, }); } - /** * post a message to the group log * @returns void @@ -268,17 +286,17 @@ export class GroupsService { groupId, requestBody, }: { - groupId: number; - requestBody: GroupMessage; + groupId: number, + requestBody: GroupMessage, }): CancelablePromise { return this.httpRequest.request({ - method: "POST", - url: "/api/v1/groups/{group_id}/send_message", + method: 'POST', + url: '/api/v1/groups/{group_id}/send_message', path: { - group_id: groupId, + 'group_id': groupId, }, body: requestBody, - mediaType: "application/json", + mediaType: 'application/json', errors: { 401: `unauthorized`, 403: `forbidden`, @@ -287,18 +305,21 @@ export class GroupsService { }, }); } - /** * list all invite links of a group * @returns GroupInvite Successful Response * @throws ApiError */ - public listInvites({ groupId }: { groupId: number }): CancelablePromise> { + public listInvites({ + groupId, + }: { + groupId: number, + }): CancelablePromise> { return this.httpRequest.request({ - method: "GET", - url: "/api/v1/groups/{group_id}/invites", + method: 'GET', + url: '/api/v1/groups/{group_id}/invites', path: { - group_id: groupId, + 'group_id': groupId, }, errors: { 401: `unauthorized`, @@ -308,7 +329,6 @@ export class GroupsService { }, }); } - /** * create a new group invite link * @returns GroupInvite Successful Response @@ -318,17 +338,17 @@ export class GroupsService { groupId, requestBody, }: { - groupId: number; - requestBody: CreateInvitePayload; + groupId: number, + requestBody: CreateInvitePayload, }): CancelablePromise { return this.httpRequest.request({ - method: "POST", - url: "/api/v1/groups/{group_id}/invites", + method: 'POST', + url: '/api/v1/groups/{group_id}/invites', path: { - group_id: groupId, + 'group_id': groupId, }, body: requestBody, - mediaType: "application/json", + mediaType: 'application/json', errors: { 401: `unauthorized`, 403: `forbidden`, @@ -337,19 +357,72 @@ export class GroupsService { }, }); } - /** * delete a group invite link * @returns void * @throws ApiError */ - public deleteInvite({ groupId, inviteId }: { groupId: number; inviteId: number }): CancelablePromise { + public deleteInvite({ + groupId, + inviteId, + }: { + groupId: number, + inviteId: number, + }): CancelablePromise { + return this.httpRequest.request({ + method: 'DELETE', + url: '/api/v1/groups/{group_id}/invites/{invite_id}', + path: { + 'group_id': groupId, + 'invite_id': inviteId, + }, + errors: { + 401: `unauthorized`, + 403: `forbidden`, + 404: `Not found`, + 422: `Validation Error`, + }, + }); + } + /** + * archive a group + * @returns any Successful Response + * @throws ApiError + */ + public archiveGroup({ + groupId, + }: { + groupId: number, + }): CancelablePromise { + return this.httpRequest.request({ + method: 'POST', + url: '/api/v1/groups/{group_id}/archive', + path: { + 'group_id': groupId, + }, + errors: { + 401: `unauthorized`, + 403: `forbidden`, + 404: `Not found`, + 422: `Validation Error`, + }, + }); + } + /** + * un-archive a group + * @returns any Successful Response + * @throws ApiError + */ + public unarchiveGroup({ + groupId, + }: { + groupId: number, + }): CancelablePromise { return this.httpRequest.request({ - method: "DELETE", - url: "/api/v1/groups/{group_id}/invites/{invite_id}", + method: 'POST', + url: '/api/v1/groups/{group_id}/un-archive', path: { - group_id: groupId, - invite_id: inviteId, + 'group_id': groupId, }, errors: { 401: `unauthorized`, diff --git a/frontend/libs/api/src/lib/generated/services/TransactionsService.ts b/frontend/libs/api/src/lib/generated/services/TransactionsService.ts index f83a77f..2edb79f 100644 --- a/frontend/libs/api/src/lib/generated/services/TransactionsService.ts +++ b/frontend/libs/api/src/lib/generated/services/TransactionsService.ts @@ -1,18 +1,15 @@ -/* generated using openapi-typescript-codegen -- do no edit */ +/* generated using openapi-typescript-codegen -- do not edit */ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { NewTransaction } from "../models/NewTransaction"; -import type { Transaction } from "../models/Transaction"; -import type { UpdatePositionsPayload } from "../models/UpdatePositionsPayload"; -import type { UpdateTransaction } from "../models/UpdateTransaction"; - -import type { CancelablePromise } from "../core/CancelablePromise"; -import type { BaseHttpRequest } from "../core/BaseHttpRequest"; - +import type { NewTransaction } from '../models/NewTransaction'; +import type { Transaction } from '../models/Transaction'; +import type { UpdatePositionsPayload } from '../models/UpdatePositionsPayload'; +import type { UpdateTransaction } from '../models/UpdateTransaction'; +import type { CancelablePromise } from '../core/CancelablePromise'; +import type { BaseHttpRequest } from '../core/BaseHttpRequest'; export class TransactionsService { constructor(public readonly httpRequest: BaseHttpRequest) {} - /** * list all transactions in a group * @returns Transaction Successful Response @@ -23,19 +20,19 @@ export class TransactionsService { minLastChanged, transactionIds, }: { - groupId: number; - minLastChanged?: string | null; - transactionIds?: string | null; + groupId: number, + minLastChanged?: (string | null), + transactionIds?: (string | null), }): CancelablePromise> { return this.httpRequest.request({ - method: "GET", - url: "/api/v1/groups/{group_id}/transactions", + method: 'GET', + url: '/api/v1/groups/{group_id}/transactions', path: { - group_id: groupId, + 'group_id': groupId, }, query: { - min_last_changed: minLastChanged, - transaction_ids: transactionIds, + 'min_last_changed': minLastChanged, + 'transaction_ids': transactionIds, }, errors: { 401: `unauthorized`, @@ -45,7 +42,6 @@ export class TransactionsService { }, }); } - /** * create a new transaction * @returns Transaction Successful Response @@ -55,17 +51,17 @@ export class TransactionsService { groupId, requestBody, }: { - groupId: number; - requestBody: NewTransaction; + groupId: number, + requestBody: NewTransaction, }): CancelablePromise { return this.httpRequest.request({ - method: "POST", - url: "/api/v1/groups/{group_id}/transactions", + method: 'POST', + url: '/api/v1/groups/{group_id}/transactions', path: { - group_id: groupId, + 'group_id': groupId, }, body: requestBody, - mediaType: "application/json", + mediaType: 'application/json', errors: { 401: `unauthorized`, 403: `forbidden`, @@ -74,18 +70,24 @@ export class TransactionsService { }, }); } - /** * get transaction details * @returns Transaction Successful Response * @throws ApiError */ - public getTransaction({ transactionId }: { transactionId: number }): CancelablePromise { + public getTransaction({ + groupId, + transactionId, + }: { + groupId: number, + transactionId: number, + }): CancelablePromise { return this.httpRequest.request({ - method: "GET", - url: "/api/v1/transactions/{transaction_id}", + method: 'GET', + url: '/api/v1/groups/{group_id}/transactions/{transaction_id}', path: { - transaction_id: transactionId, + 'group_id': groupId, + 'transaction_id': transactionId, }, errors: { 401: `unauthorized`, @@ -95,27 +97,29 @@ export class TransactionsService { }, }); } - /** * update transaction details * @returns Transaction Successful Response * @throws ApiError */ public updateTransaction({ + groupId, transactionId, requestBody, }: { - transactionId: number; - requestBody: UpdateTransaction; + groupId: number, + transactionId: number, + requestBody: UpdateTransaction, }): CancelablePromise { return this.httpRequest.request({ - method: "POST", - url: "/api/v1/transactions/{transaction_id}", + method: 'POST', + url: '/api/v1/groups/{group_id}/transactions/{transaction_id}', path: { - transaction_id: transactionId, + 'group_id': groupId, + 'transaction_id': transactionId, }, body: requestBody, - mediaType: "application/json", + mediaType: 'application/json', errors: { 401: `unauthorized`, 403: `forbidden`, @@ -124,18 +128,24 @@ export class TransactionsService { }, }); } - /** * delete a transaction * @returns Transaction Successful Response * @throws ApiError */ - public deleteTransaction({ transactionId }: { transactionId: number }): CancelablePromise { + public deleteTransaction({ + groupId, + transactionId, + }: { + groupId: number, + transactionId: number, + }): CancelablePromise { return this.httpRequest.request({ - method: "DELETE", - url: "/api/v1/transactions/{transaction_id}", + method: 'DELETE', + url: '/api/v1/groups/{group_id}/transactions/{transaction_id}', path: { - transaction_id: transactionId, + 'group_id': groupId, + 'transaction_id': transactionId, }, errors: { 401: `unauthorized`, @@ -145,27 +155,29 @@ export class TransactionsService { }, }); } - /** * update transaction positions * @returns Transaction Successful Response * @throws ApiError */ public updateTransactionPositions({ + groupId, transactionId, requestBody, }: { - transactionId: number; - requestBody: UpdatePositionsPayload; + groupId: number, + transactionId: number, + requestBody: UpdatePositionsPayload, }): CancelablePromise { return this.httpRequest.request({ - method: "POST", - url: "/api/v1/transactions/{transaction_id}/positions", + method: 'POST', + url: '/api/v1/groups/{group_id}/transactions/{transaction_id}/positions', path: { - transaction_id: transactionId, + 'group_id': groupId, + 'transaction_id': transactionId, }, body: requestBody, - mediaType: "application/json", + mediaType: 'application/json', errors: { 401: `unauthorized`, 403: `forbidden`, @@ -174,19 +186,24 @@ export class TransactionsService { }, }); } - /** * fetch the (binary) contents of a transaction attachment * @returns any Successful Response * @throws ApiError */ - public getFileContents({ fileId, blobId }: { fileId: number; blobId: number }): CancelablePromise { + public getFileContents({ + fileId, + blobId, + }: { + fileId: number, + blobId: number, + }): CancelablePromise { return this.httpRequest.request({ - method: "GET", - url: "/api/v1/files/{file_id}/{blob_id}", + method: 'GET', + url: '/api/v1/files/{file_id}/{blob_id}', path: { - file_id: fileId, - blob_id: blobId, + 'file_id': fileId, + 'blob_id': blobId, }, errors: { 401: `unauthorized`, diff --git a/frontend/libs/redux/src/index.ts b/frontend/libs/redux/src/index.ts index 1872f96..a2e9163 100644 --- a/frontend/libs/redux/src/index.ts +++ b/frontend/libs/redux/src/index.ts @@ -8,3 +8,4 @@ export * from "./lib/subscriptions"; export * from "./lib/transactions"; export * from "./lib/types"; export * from "./lib/thunks"; +export * from "./lib/hooks"; diff --git a/frontend/libs/redux/src/lib/accounts/accountSlice.ts b/frontend/libs/redux/src/lib/accounts/accountSlice.ts index cbd6a26..bfd61d1 100644 --- a/frontend/libs/redux/src/lib/accounts/accountSlice.ts +++ b/frontend/libs/redux/src/lib/accounts/accountSlice.ts @@ -204,12 +204,13 @@ export const fetchAccounts = createAsyncThunk< } ); -export const fetchAccount = createAsyncThunk( - "fetchAccount", - async ({ accountId, api }) => { - return await api.client.accounts.getAccount({ accountId }); - } -); +export const fetchAccount = createAsyncThunk< + BackendAccount, + { groupId: number; accountId: number; api: Api }, + { state: IRootState } +>("fetchAccount", async ({ groupId, accountId, api }) => { + return await api.client.accounts.getAccount({ groupId, accountId }); +}); export const saveAccount = createAsyncThunk< { oldAccountId: number; account: BackendAccount }, @@ -231,6 +232,7 @@ export const saveAccount = createAsyncThunk< }); } else { updatedAccount = await api.client.accounts.updateAccount({ + groupId, accountId: wipAccount.id, requestBody: { owning_user_id: null, tags: [], date_info: null, ...wipAccount }, }); @@ -295,7 +297,7 @@ export const deleteAccount = createAsyncThunk< const account = s.accounts.byId[accountId]; if (account) { if (await api.hasConnection()) { - const backendAccount = await api.client.accounts.deleteAccount({ accountId }); + const backendAccount = await api.client.accounts.deleteAccount({ groupId, accountId }); return { account: backendAccount }; } else { return rejectWithValue("no internet connection"); diff --git a/frontend/libs/redux/src/lib/context/AbrechnungUpdateProvider.tsx b/frontend/libs/redux/src/lib/context/AbrechnungUpdateProvider.tsx index ef69185..c30ae33 100644 --- a/frontend/libs/redux/src/lib/context/AbrechnungUpdateProvider.tsx +++ b/frontend/libs/redux/src/lib/context/AbrechnungUpdateProvider.tsx @@ -37,10 +37,22 @@ export const AbrechnungUpdateProvider: React.FC = ({ const callback = (notificationPayload: NotificationPayload) => { switch (notificationPayload.type) { case "account": - dispatch(fetchAccount({ api, accountId: notificationPayload.accountId })); + dispatch( + fetchAccount({ + api, + groupId: notificationPayload.groupId, + accountId: notificationPayload.accountId, + }) + ); break; case "transaction": - dispatch(fetchTransaction({ api, transactionId: notificationPayload.transactionId })); + dispatch( + fetchTransaction({ + api, + groupId: notificationPayload.groupId, + transactionId: notificationPayload.transactionId, + }) + ); break; case "group": dispatch(fetchGroups({ api })); diff --git a/frontend/libs/redux/src/lib/groups/actions.ts b/frontend/libs/redux/src/lib/groups/actions.ts index 0a421f8..963e327 100644 --- a/frontend/libs/redux/src/lib/groups/actions.ts +++ b/frontend/libs/redux/src/lib/groups/actions.ts @@ -8,3 +8,17 @@ export const leaveGroup = createAsyncThunk( + "archiveGroup", + async ({ groupId, api }) => { + await api.client.groups.archiveGroup({ groupId }); + } +); + +export const unarchiveGroup = createAsyncThunk( + "unarchiveGroup", + async ({ groupId, api }) => { + await api.client.groups.unarchiveGroup({ groupId }); + } +); diff --git a/frontend/libs/redux/src/lib/groups/groupSlice.ts b/frontend/libs/redux/src/lib/groups/groupSlice.ts index b31990b..a4fe1ff 100644 --- a/frontend/libs/redux/src/lib/groups/groupSlice.ts +++ b/frontend/libs/redux/src/lib/groups/groupSlice.ts @@ -1,6 +1,6 @@ import { Api, Group, GroupInvite, GroupLog, GroupMember, GroupPayload } from "@abrechnung/api"; import { GroupPermissions } from "@abrechnung/types"; -import { lambdaComparator } from "@abrechnung/utils"; +import { fromISOString, lambdaComparator } from "@abrechnung/utils"; import { Draft, createAsyncThunk, createSelector, createSlice } from "@reduxjs/toolkit"; import { GroupInfo, GroupSliceState, IRootState, StateStatus } from "../types"; import { addEntity, getGroupScopedState, removeEntity } from "../utils"; @@ -43,11 +43,19 @@ const initializeGroupState = (state: Draft, groupId: number) => const selectGroupSlice = (state: IRootState, groupId: number) => getGroupScopedState(state.groups, groupId); +const groupSortFn = (lhs: Group, rhs: Group): number => { + return fromISOString(rhs.last_changed).getTime() - fromISOString(lhs.last_changed).getTime(); +}; + // selectors export const selectGroups = createSelector( (state: IRootState) => state.groups, - (state: GroupSliceState) => { - return state.groups.ids.map((id) => state.groups.byId[id]); + (state: IRootState, archived: boolean) => archived, + (state: GroupSliceState, archived: boolean) => { + return state.groups.ids + .map((id) => state.groups.byId[id]) + .filter((group) => group.archived === archived) + .sort(groupSortFn); } ); diff --git a/frontend/libs/redux/src/lib/hooks/index.ts b/frontend/libs/redux/src/lib/hooks/index.ts new file mode 100644 index 0000000..a4a9cb6 --- /dev/null +++ b/frontend/libs/redux/src/lib/hooks/index.ts @@ -0,0 +1 @@ +export * from "./useIsGroupWritable"; diff --git a/frontend/libs/redux/src/lib/hooks/useIsGroupWritable.tsx b/frontend/libs/redux/src/lib/hooks/useIsGroupWritable.tsx new file mode 100644 index 0000000..479e9bd --- /dev/null +++ b/frontend/libs/redux/src/lib/hooks/useIsGroupWritable.tsx @@ -0,0 +1,13 @@ +import { useGroup } from "../groups"; +import { useCurrentUserPermissions } from "../selectors"; + +export const useIsGroupWritable = (groupId: number) => { + const permissions = useCurrentUserPermissions(groupId); + const group = useGroup(groupId); + + if (!permissions || !group) { + return false; + } + + return permissions.can_write && !group.archived; +}; diff --git a/frontend/libs/redux/src/lib/transactions/transactionSlice.ts b/frontend/libs/redux/src/lib/transactions/transactionSlice.ts index 43946b2..a0ffb2d 100644 --- a/frontend/libs/redux/src/lib/transactions/transactionSlice.ts +++ b/frontend/libs/redux/src/lib/transactions/transactionSlice.ts @@ -1,4 +1,3 @@ -import * as React from "react"; import { Api, NewFile, @@ -234,10 +233,10 @@ export const fetchTransactions = createAsyncThunk< export const fetchTransaction = createAsyncThunk< BackendTransaction, - { transactionId: number; api: Api }, + { groupId: number; transactionId: number; api: Api }, { state: IRootState } ->("fetchTransaction", async ({ transactionId, api }) => { - return await api.client.transactions.getTransaction({ transactionId }); +>("fetchTransaction", async ({ groupId, transactionId, api }) => { + return await api.client.transactions.getTransaction({ groupId, transactionId }); }); export const createTransaction = createAsyncThunk< @@ -363,6 +362,7 @@ export const saveTransaction = createAsyncThunk< }); } else { updatedTransaction = await api.client.transactions.updateTransaction({ + groupId, transactionId: wipTransaction.id, requestBody: { ...body, @@ -391,7 +391,7 @@ export const deleteTransaction = createAsyncThunk< const transaction = s.transactions.byId[transactionId]; if (transaction) { if (await api.hasConnection()) { - const backendTransaction = await api.client.transactions.deleteTransaction({ transactionId }); + const backendTransaction = await api.client.transactions.deleteTransaction({ groupId, transactionId }); return { transaction: backendTransaction }; } else { return rejectWithValue("no internet connection"); diff --git a/frontend/libs/translations/src/lib/en.ts b/frontend/libs/translations/src/lib/en.ts index d4ad4dc..c2f18c9 100644 --- a/frontend/libs/translations/src/lib/en.ts +++ b/frontend/libs/translations/src/lib/en.ts @@ -40,6 +40,7 @@ const translations = { currency: "Currency", addNewTag: "Add new Tag", exportAsCsv: "Export as CSV", + noneSoFar: "None so far", }, shareSelect: { selectedPeople_one: "{{count}} Person", @@ -67,9 +68,11 @@ const translations = { }, groups: { addGroup: "Add Group", + archivedDisclaimer: "This group is archived and therefore read-only.", list: { tabTitle: "Abrechnung - Groups", header: "Groups", + archivedGroups: "Archived", guestUserDisclaimer: "You are a guest user on this Abrechnung and therefore not permitted to create new groups.", noGroups: "No Groups", @@ -99,6 +102,12 @@ const translations = { leaveGroup: "Leave Group", leaveGroupConfirm: "Are you sure you want to leave the group {{group.name}}. If you are the last member to leave this group it will be deleted and its transaction will be lost forever...", + archiveGroup: "Archive Group", + archiveGroupConfirm: + "Are you sure you want to archive the group {{group.name}}. No modifications can be made to archived groups and they will be hidden in group lists. Only a group owner can reverse this action.", + unarchiveGroup: "Unarchive Group", + unarchiveGroupConfirm: + "Are you sure you want to unarchive the group {{group.name}}. The group will no longer be read-only.", }, join: { tabTitle: "Abrechnung - Join Group", diff --git a/frontend/nx.json b/frontend/nx.json index e9f023a..9185185 100644 --- a/frontend/nx.json +++ b/frontend/nx.json @@ -1,8 +1,6 @@ { "$schema": "./node_modules/nx/schemas/nx-schema.json", - "affected": { - "defaultBase": "main" - }, + "parallel": 8, "pluginsConfig": { "@nx/js": { "analyzeSourceFiles": false From cd9129feb0cfbd931a2485d093ed4d69ed56b733 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Loipf=C3=BChrer?= Date: Sun, 8 Sep 2024 18:07:20 +0200 Subject: [PATCH 7/9] refactor(web): switch group create modal to react-hook-form --- .../apps/web/src/components/FormTextField.tsx | 2 +- .../components/groups/GroupCreateModal.tsx | 130 +++++++----------- 2 files changed, 50 insertions(+), 82 deletions(-) diff --git a/frontend/apps/web/src/components/FormTextField.tsx b/frontend/apps/web/src/components/FormTextField.tsx index d21c86b..3270813 100644 --- a/frontend/apps/web/src/components/FormTextField.tsx +++ b/frontend/apps/web/src/components/FormTextField.tsx @@ -4,7 +4,7 @@ import { TextField, TextFieldProps } from "@mui/material"; export type FormTextFieldProps = Omit & { name: string; - control: Control; + control: Control; }; export const FormTextField = ({ name, control, ...props }: FormTextFieldProps) => { diff --git a/frontend/apps/web/src/components/groups/GroupCreateModal.tsx b/frontend/apps/web/src/components/groups/GroupCreateModal.tsx index a00d7da..99c03b9 100644 --- a/frontend/apps/web/src/components/groups/GroupCreateModal.tsx +++ b/frontend/apps/web/src/components/groups/GroupCreateModal.tsx @@ -1,22 +1,13 @@ import { createGroup } from "@abrechnung/redux"; -import { - Button, - Checkbox, - Dialog, - DialogActions, - DialogContent, - DialogTitle, - FormControlLabel, - LinearProgress, - TextField, -} from "@mui/material"; -import { Form, Formik, FormikHelpers, FormikProps } from "formik"; -import React, { ReactNode } from "react"; +import { Button, Checkbox, Dialog, DialogActions, DialogContent, DialogTitle, FormControlLabel } from "@mui/material"; +import * as React from "react"; import { toast } from "react-toastify"; import { z } from "zod"; import { api } from "@/core/api"; import { useAppDispatch } from "@/store"; -import { toFormikValidationSchema } from "@abrechnung/utils"; +import { Controller, useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { FormTextField } from "../FormTextField"; const validationSchema = z.object({ name: z.string({ required_error: "Name is required" }), @@ -39,8 +30,12 @@ interface Props { export const GroupCreateModal: React.FC = ({ show, onClose }) => { const dispatch = useAppDispatch(); + const { control, handleSubmit } = useForm({ + resolver: zodResolver(validationSchema), + defaultValues: initialValues, + }); - const handleSubmit = (values: FormValues, { setSubmitting }: FormikHelpers) => { + const onSubmit = (values: FormValues) => { dispatch( createGroup({ api, @@ -55,12 +50,10 @@ export const GroupCreateModal: React.FC = ({ show, onClose }) => { ) .unwrap() .then(() => { - setSubmitting(false); onClose("completed"); }) .catch((err) => { toast.error(err); - setSubmitting(false); }); }; @@ -68,71 +61,46 @@ export const GroupCreateModal: React.FC = ({ show, onClose }) => { onClose(reason)}> Create Group - - {({ - values, - touched, - errors, - handleBlur, - handleChange, - isSubmitting, - setFieldValue, - }: FormikProps) => ( -
- + + + } /> - - setFieldValue("addUserAccountOnJoin", e.target.checked)} - checked={values.addUserAccountOnJoin} - /> - } - label="Automatically add accounts for newly joined group members" - /> - {isSubmitting && } - - - - - - )} -
+ } + /> + + + + +
); From 4c9ebc3a9ff7b173f44f02d93025558e9e59b5c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Loipf=C3=BChrer?= Date: Sun, 8 Sep 2024 18:12:25 +0200 Subject: [PATCH 8/9] chore: formatting --- abrechnung/core/decorators.py | 7 +- frontend/libs/api/src/lib/generated/Client.ts | 23 +- .../api/src/lib/generated/core/ApiError.ts | 6 +- .../lib/generated/core/ApiRequestOptions.ts | 2 +- .../src/lib/generated/core/BaseHttpRequest.ts | 7 +- .../lib/generated/core/CancelablePromise.ts | 13 +- .../lib/generated/core/FetchHttpRequest.ts | 11 +- .../api/src/lib/generated/core/OpenAPI.ts | 10 +- .../api/src/lib/generated/core/request.ts | 103 +- frontend/libs/api/src/lib/generated/index.ts | 106 +- .../src/lib/generated/models/AccountType.ts | 2 +- .../lib/generated/models/Body_get_token.ts | 7 +- .../generated/models/ChangeEmailPayload.ts | 1 - .../generated/models/ChangePasswordPayload.ts | 1 - .../lib/generated/models/ClearingAccount.ts | 1 - .../models/ConfirmEmailChangePayload.ts | 1 - .../models/ConfirmPasswordRecoveryPayload.ts | 1 - .../models/ConfirmRegistrationPayload.ts | 1 - .../generated/models/CreateInvitePayload.ts | 1 - .../generated/models/DeleteSessionPayload.ts | 1 - .../lib/generated/models/FileAttachment.ts | 7 +- .../api/src/lib/generated/models/Group.ts | 1 - .../src/lib/generated/models/GroupInvite.ts | 3 +- .../api/src/lib/generated/models/GroupLog.ts | 3 +- .../src/lib/generated/models/GroupMember.ts | 3 +- .../src/lib/generated/models/GroupMessage.ts | 1 - .../src/lib/generated/models/GroupPayload.ts | 1 - .../src/lib/generated/models/GroupPreview.ts | 1 - .../generated/models/HTTPValidationError.ts | 3 +- .../src/lib/generated/models/LoginPayload.ts | 1 - .../src/lib/generated/models/NewAccount.ts | 7 +- .../api/src/lib/generated/models/NewFile.ts | 1 - .../lib/generated/models/NewTransaction.ts | 7 +- .../models/NewTransactionPosition.ts | 1 - .../lib/generated/models/PersonalAccount.ts | 3 +- .../generated/models/PreviewGroupPayload.ts | 1 - .../models/RecoverPasswordPayload.ts | 1 - .../lib/generated/models/RegisterPayload.ts | 3 +- .../lib/generated/models/RegisterResponse.ts | 1 - .../generated/models/RenameSessionPayload.ts | 1 - .../api/src/lib/generated/models/Session.ts | 3 +- .../api/src/lib/generated/models/Token.ts | 1 - .../src/lib/generated/models/Transaction.ts | 7 +- .../generated/models/TransactionPosition.ts | 1 - .../lib/generated/models/TransactionType.ts | 2 +- .../src/lib/generated/models/UpdateFile.ts | 1 - .../models/UpdateGroupMemberPayload.ts | 1 - .../models/UpdatePositionsPayload.ts | 3 +- .../lib/generated/models/UpdateTransaction.ts | 11 +- .../libs/api/src/lib/generated/models/User.ts | 3 +- .../lib/generated/models/ValidationError.ts | 3 +- .../lib/generated/models/VersionResponse.ts | 1 - frontend/libs/api/src/lib/generated/schema.ts | 3138 +++++++++-------- .../lib/generated/services/AccountsService.ts | 82 +- .../src/lib/generated/services/AuthService.ts | 168 +- .../lib/generated/services/CommonService.ts | 10 +- .../lib/generated/services/GroupsService.ts | 224 +- .../generated/services/TransactionsService.ts | 112 +- 58 files changed, 2002 insertions(+), 2124 deletions(-) diff --git a/abrechnung/core/decorators.py b/abrechnung/core/decorators.py index eba3799..c01beb8 100644 --- a/abrechnung/core/decorators.py +++ b/abrechnung/core/decorators.py @@ -1,5 +1,5 @@ from functools import wraps -from inspect import signature, Parameter +from inspect import Parameter, signature from typing import Awaitable, Callable, TypeVar from abrechnung.core.auth import check_group_permissions @@ -11,7 +11,9 @@ def _add_arg_to_signature(original_func, new_func, name: str, annotation): sig = signature(original_func) if name in sig.parameters: return - new_parameters = tuple(sig.parameters.values()) + (Parameter(name, kind=Parameter.KEYWORD_ONLY, annotation=annotation),) + new_parameters = tuple(sig.parameters.values()) + ( + Parameter(name, kind=Parameter.KEYWORD_ONLY, annotation=annotation), + ) sig = sig.replace(parameters=new_parameters) new_func.__signature__ = sig # type: ignore @@ -78,6 +80,7 @@ async def wrapper(*args, **kwargs): kwargs["group_id"] = group_id return await func(*args, **kwargs) + _add_arg_to_signature(func, wrapper, "group_id", int) return wrapper diff --git a/frontend/libs/api/src/lib/generated/Client.ts b/frontend/libs/api/src/lib/generated/Client.ts index 90ce597..62fde6a 100644 --- a/frontend/libs/api/src/lib/generated/Client.ts +++ b/frontend/libs/api/src/lib/generated/Client.ts @@ -2,14 +2,14 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { BaseHttpRequest } from './core/BaseHttpRequest'; -import type { OpenAPIConfig } from './core/OpenAPI'; -import { FetchHttpRequest } from './core/FetchHttpRequest'; -import { AccountsService } from './services/AccountsService'; -import { AuthService } from './services/AuthService'; -import { CommonService } from './services/CommonService'; -import { GroupsService } from './services/GroupsService'; -import { TransactionsService } from './services/TransactionsService'; +import type { BaseHttpRequest } from "./core/BaseHttpRequest"; +import type { OpenAPIConfig } from "./core/OpenAPI"; +import { FetchHttpRequest } from "./core/FetchHttpRequest"; +import { AccountsService } from "./services/AccountsService"; +import { AuthService } from "./services/AuthService"; +import { CommonService } from "./services/CommonService"; +import { GroupsService } from "./services/GroupsService"; +import { TransactionsService } from "./services/TransactionsService"; type HttpRequestConstructor = new (config: OpenAPIConfig) => BaseHttpRequest; export class Client { public readonly accounts: AccountsService; @@ -20,10 +20,10 @@ export class Client { public readonly request: BaseHttpRequest; constructor(config?: Partial, HttpRequest: HttpRequestConstructor = FetchHttpRequest) { this.request = new HttpRequest({ - BASE: config?.BASE ?? '', - VERSION: config?.VERSION ?? '0.14.0', + BASE: config?.BASE ?? "", + VERSION: config?.VERSION ?? "0.14.0", WITH_CREDENTIALS: config?.WITH_CREDENTIALS ?? false, - CREDENTIALS: config?.CREDENTIALS ?? 'include', + CREDENTIALS: config?.CREDENTIALS ?? "include", TOKEN: config?.TOKEN, USERNAME: config?.USERNAME, PASSWORD: config?.PASSWORD, @@ -37,4 +37,3 @@ export class Client { this.transactions = new TransactionsService(this.request); } } - diff --git a/frontend/libs/api/src/lib/generated/core/ApiError.ts b/frontend/libs/api/src/lib/generated/core/ApiError.ts index ec7b16a..360272a 100644 --- a/frontend/libs/api/src/lib/generated/core/ApiError.ts +++ b/frontend/libs/api/src/lib/generated/core/ApiError.ts @@ -2,8 +2,8 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { ApiRequestOptions } from './ApiRequestOptions'; -import type { ApiResult } from './ApiResult'; +import type { ApiRequestOptions } from "./ApiRequestOptions"; +import type { ApiResult } from "./ApiResult"; export class ApiError extends Error { public readonly url: string; @@ -15,7 +15,7 @@ export class ApiError extends Error { constructor(request: ApiRequestOptions, response: ApiResult, message: string) { super(message); - this.name = 'ApiError'; + this.name = "ApiError"; this.url = response.url; this.status = response.status; this.statusText = response.statusText; diff --git a/frontend/libs/api/src/lib/generated/core/ApiRequestOptions.ts b/frontend/libs/api/src/lib/generated/core/ApiRequestOptions.ts index 93143c3..b0f8271 100644 --- a/frontend/libs/api/src/lib/generated/core/ApiRequestOptions.ts +++ b/frontend/libs/api/src/lib/generated/core/ApiRequestOptions.ts @@ -3,7 +3,7 @@ /* tslint:disable */ /* eslint-disable */ export type ApiRequestOptions = { - readonly method: 'GET' | 'PUT' | 'POST' | 'DELETE' | 'OPTIONS' | 'HEAD' | 'PATCH'; + readonly method: "GET" | "PUT" | "POST" | "DELETE" | "OPTIONS" | "HEAD" | "PATCH"; readonly url: string; readonly path?: Record; readonly cookies?: Record; diff --git a/frontend/libs/api/src/lib/generated/core/BaseHttpRequest.ts b/frontend/libs/api/src/lib/generated/core/BaseHttpRequest.ts index 04aad6a..0fdd849 100644 --- a/frontend/libs/api/src/lib/generated/core/BaseHttpRequest.ts +++ b/frontend/libs/api/src/lib/generated/core/BaseHttpRequest.ts @@ -2,12 +2,11 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { ApiRequestOptions } from './ApiRequestOptions'; -import type { CancelablePromise } from './CancelablePromise'; -import type { OpenAPIConfig } from './OpenAPI'; +import type { ApiRequestOptions } from "./ApiRequestOptions"; +import type { CancelablePromise } from "./CancelablePromise"; +import type { OpenAPIConfig } from "./OpenAPI"; export abstract class BaseHttpRequest { - constructor(public readonly config: OpenAPIConfig) {} public abstract request(options: ApiRequestOptions): CancelablePromise; diff --git a/frontend/libs/api/src/lib/generated/core/CancelablePromise.ts b/frontend/libs/api/src/lib/generated/core/CancelablePromise.ts index d70de92..183e413 100644 --- a/frontend/libs/api/src/lib/generated/core/CancelablePromise.ts +++ b/frontend/libs/api/src/lib/generated/core/CancelablePromise.ts @@ -3,10 +3,9 @@ /* tslint:disable */ /* eslint-disable */ export class CancelError extends Error { - constructor(message: string) { super(message); - this.name = 'CancelError'; + this.name = "CancelError"; } public get isCancelled(): boolean { @@ -69,15 +68,15 @@ export class CancelablePromise implements Promise { this.#cancelHandlers.push(cancelHandler); }; - Object.defineProperty(onCancel, 'isResolved', { + Object.defineProperty(onCancel, "isResolved", { get: (): boolean => this.#isResolved, }); - Object.defineProperty(onCancel, 'isRejected', { + Object.defineProperty(onCancel, "isRejected", { get: (): boolean => this.#isRejected, }); - Object.defineProperty(onCancel, 'isCancelled', { + Object.defineProperty(onCancel, "isCancelled", { get: (): boolean => this.#isCancelled, }); @@ -117,12 +116,12 @@ export class CancelablePromise implements Promise { cancelHandler(); } } catch (error) { - console.warn('Cancellation threw an error', error); + console.warn("Cancellation threw an error", error); return; } } this.#cancelHandlers.length = 0; - if (this.#reject) this.#reject(new CancelError('Request aborted')); + if (this.#reject) this.#reject(new CancelError("Request aborted")); } public get isCancelled(): boolean { diff --git a/frontend/libs/api/src/lib/generated/core/FetchHttpRequest.ts b/frontend/libs/api/src/lib/generated/core/FetchHttpRequest.ts index e58111a..eaf9466 100644 --- a/frontend/libs/api/src/lib/generated/core/FetchHttpRequest.ts +++ b/frontend/libs/api/src/lib/generated/core/FetchHttpRequest.ts @@ -2,14 +2,13 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { ApiRequestOptions } from './ApiRequestOptions'; -import { BaseHttpRequest } from './BaseHttpRequest'; -import type { CancelablePromise } from './CancelablePromise'; -import type { OpenAPIConfig } from './OpenAPI'; -import { request as __request } from './request'; +import type { ApiRequestOptions } from "./ApiRequestOptions"; +import { BaseHttpRequest } from "./BaseHttpRequest"; +import type { CancelablePromise } from "./CancelablePromise"; +import type { OpenAPIConfig } from "./OpenAPI"; +import { request as __request } from "./request"; export class FetchHttpRequest extends BaseHttpRequest { - constructor(config: OpenAPIConfig) { super(config); } diff --git a/frontend/libs/api/src/lib/generated/core/OpenAPI.ts b/frontend/libs/api/src/lib/generated/core/OpenAPI.ts index 76e30d8..1731d2b 100644 --- a/frontend/libs/api/src/lib/generated/core/OpenAPI.ts +++ b/frontend/libs/api/src/lib/generated/core/OpenAPI.ts @@ -2,7 +2,7 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { ApiRequestOptions } from './ApiRequestOptions'; +import type { ApiRequestOptions } from "./ApiRequestOptions"; type Resolver = (options: ApiRequestOptions) => Promise; type Headers = Record; @@ -11,7 +11,7 @@ export type OpenAPIConfig = { BASE: string; VERSION: string; WITH_CREDENTIALS: boolean; - CREDENTIALS: 'include' | 'omit' | 'same-origin'; + CREDENTIALS: "include" | "omit" | "same-origin"; TOKEN?: string | Resolver | undefined; USERNAME?: string | Resolver | undefined; PASSWORD?: string | Resolver | undefined; @@ -20,10 +20,10 @@ export type OpenAPIConfig = { }; export const OpenAPI: OpenAPIConfig = { - BASE: '', - VERSION: '0.14.0', + BASE: "", + VERSION: "0.14.0", WITH_CREDENTIALS: false, - CREDENTIALS: 'include', + CREDENTIALS: "include", TOKEN: undefined, USERNAME: undefined, PASSWORD: undefined, diff --git a/frontend/libs/api/src/lib/generated/core/request.ts b/frontend/libs/api/src/lib/generated/core/request.ts index f83d711..2ab4d6c 100644 --- a/frontend/libs/api/src/lib/generated/core/request.ts +++ b/frontend/libs/api/src/lib/generated/core/request.ts @@ -2,33 +2,33 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import { ApiError } from './ApiError'; -import type { ApiRequestOptions } from './ApiRequestOptions'; -import type { ApiResult } from './ApiResult'; -import { CancelablePromise } from './CancelablePromise'; -import type { OnCancel } from './CancelablePromise'; -import type { OpenAPIConfig } from './OpenAPI'; +import { ApiError } from "./ApiError"; +import type { ApiRequestOptions } from "./ApiRequestOptions"; +import type { ApiResult } from "./ApiResult"; +import { CancelablePromise } from "./CancelablePromise"; +import type { OnCancel } from "./CancelablePromise"; +import type { OpenAPIConfig } from "./OpenAPI"; export const isDefined = (value: T | null | undefined): value is Exclude => { return value !== undefined && value !== null; }; export const isString = (value: any): value is string => { - return typeof value === 'string'; + return typeof value === "string"; }; export const isStringWithValue = (value: any): value is string => { - return isString(value) && value !== ''; + return isString(value) && value !== ""; }; export const isBlob = (value: any): value is Blob => { return ( - typeof value === 'object' && - typeof value.type === 'string' && - typeof value.stream === 'function' && - typeof value.arrayBuffer === 'function' && - typeof value.constructor === 'function' && - typeof value.constructor.name === 'string' && + typeof value === "object" && + typeof value.type === "string" && + typeof value.stream === "function" && + typeof value.arrayBuffer === "function" && + typeof value.constructor === "function" && + typeof value.constructor.name === "string" && /^(Blob|File)$/.test(value.constructor.name) && /^(Blob|File)$/.test(value[Symbol.toStringTag]) ); @@ -43,7 +43,7 @@ export const base64 = (str: string): string => { return btoa(str); } catch (err) { // @ts-ignore - return Buffer.from(str).toString('base64'); + return Buffer.from(str).toString("base64"); } }; @@ -57,10 +57,10 @@ export const getQueryString = (params: Record): string => { const process = (key: string, value: any) => { if (isDefined(value)) { if (Array.isArray(value)) { - value.forEach(v => { + value.forEach((v) => { process(key, v); }); - } else if (typeof value === 'object') { + } else if (typeof value === "object") { Object.entries(value).forEach(([k, v]) => { process(`${key}[${k}]`, v); }); @@ -75,17 +75,17 @@ export const getQueryString = (params: Record): string => { }); if (qs.length > 0) { - return `?${qs.join('&')}`; + return `?${qs.join("&")}`; } - return ''; + return ""; }; const getUrl = (config: OpenAPIConfig, options: ApiRequestOptions): string => { const encoder = config.ENCODE_PATH || encodeURI; const path = options.url - .replace('{api-version}', config.VERSION) + .replace("{api-version}", config.VERSION) .replace(/{(.*?)}/g, (substring: string, group: string) => { if (options.path?.hasOwnProperty(group)) { return encoder(String(options.path[group])); @@ -116,7 +116,7 @@ export const getFormData = (options: ApiRequestOptions): FormData | undefined => .filter(([_, value]) => isDefined(value)) .forEach(([key, value]) => { if (Array.isArray(value)) { - value.forEach(v => process(key, v)); + value.forEach((v) => process(key, v)); } else { process(key, value); } @@ -130,7 +130,7 @@ export const getFormData = (options: ApiRequestOptions): FormData | undefined => type Resolver = (options: ApiRequestOptions) => Promise; export const resolve = async (options: ApiRequestOptions, resolver?: T | Resolver): Promise => { - if (typeof resolver === 'function') { + if (typeof resolver === "function") { return (resolver as Resolver)(options); } return resolver; @@ -145,34 +145,37 @@ export const getHeaders = async (config: OpenAPIConfig, options: ApiRequestOptio ]); const headers = Object.entries({ - Accept: 'application/json', + Accept: "application/json", ...additionalHeaders, ...options.headers, }) .filter(([_, value]) => isDefined(value)) - .reduce((headers, [key, value]) => ({ - ...headers, - [key]: String(value), - }), {} as Record); + .reduce( + (headers, [key, value]) => ({ + ...headers, + [key]: String(value), + }), + {} as Record + ); if (isStringWithValue(token)) { - headers['Authorization'] = `Bearer ${token}`; + headers["Authorization"] = `Bearer ${token}`; } if (isStringWithValue(username) && isStringWithValue(password)) { const credentials = base64(`${username}:${password}`); - headers['Authorization'] = `Basic ${credentials}`; + headers["Authorization"] = `Basic ${credentials}`; } if (options.body !== undefined) { if (options.mediaType) { - headers['Content-Type'] = options.mediaType; + headers["Content-Type"] = options.mediaType; } else if (isBlob(options.body)) { - headers['Content-Type'] = options.body.type || 'application/octet-stream'; + headers["Content-Type"] = options.body.type || "application/octet-stream"; } else if (isString(options.body)) { - headers['Content-Type'] = 'text/plain'; + headers["Content-Type"] = "text/plain"; } else if (!isFormData(options.body)) { - headers['Content-Type'] = 'application/json'; + headers["Content-Type"] = "application/json"; } } @@ -181,8 +184,8 @@ export const getHeaders = async (config: OpenAPIConfig, options: ApiRequestOptio export const getRequestBody = (options: ApiRequestOptions): any => { if (options.body !== undefined) { - if (options.mediaType?.includes('/json')) { - return JSON.stringify(options.body) + if (options.mediaType?.includes("/json")) { + return JSON.stringify(options.body); } else if (isString(options.body) || isBlob(options.body) || isFormData(options.body)) { return options.body; } else { @@ -232,10 +235,10 @@ export const getResponseHeader = (response: Response, responseHeader?: string): export const getResponseBody = async (response: Response): Promise => { if (response.status !== 204) { try { - const contentType = response.headers.get('Content-Type'); + const contentType = response.headers.get("Content-Type"); if (contentType) { - const jsonTypes = ['application/json', 'application/problem+json'] - const isJSON = jsonTypes.some(type => contentType.toLowerCase().startsWith(type)); + const jsonTypes = ["application/json", "application/problem+json"]; + const isJSON = jsonTypes.some((type) => contentType.toLowerCase().startsWith(type)); if (isJSON) { return await response.json(); } else { @@ -251,15 +254,15 @@ export const getResponseBody = async (response: Response): Promise => { export const catchErrorCodes = (options: ApiRequestOptions, result: ApiResult): void => { const errors: Record = { - 400: 'Bad Request', - 401: 'Unauthorized', - 403: 'Forbidden', - 404: 'Not Found', - 500: 'Internal Server Error', - 502: 'Bad Gateway', - 503: 'Service Unavailable', + 400: "Bad Request", + 401: "Unauthorized", + 403: "Forbidden", + 404: "Not Found", + 500: "Internal Server Error", + 502: "Bad Gateway", + 503: "Service Unavailable", ...options.errors, - } + }; const error = errors[result.status]; if (error) { @@ -267,8 +270,8 @@ export const catchErrorCodes = (options: ApiRequestOptions, result: ApiResult): } if (!result.ok) { - const errorStatus = result.status ?? 'unknown'; - const errorStatusText = result.statusText ?? 'unknown'; + const errorStatus = result.status ?? "unknown"; + const errorStatusText = result.statusText ?? "unknown"; const errorBody = (() => { try { return JSON.stringify(result.body, null, 2); @@ -277,7 +280,9 @@ export const catchErrorCodes = (options: ApiRequestOptions, result: ApiResult): } })(); - throw new ApiError(options, result, + throw new ApiError( + options, + result, `Generic Error: status: ${errorStatus}; status text: ${errorStatusText}; body: ${errorBody}` ); } diff --git a/frontend/libs/api/src/lib/generated/index.ts b/frontend/libs/api/src/lib/generated/index.ts index 1f94b39..2ec668a 100644 --- a/frontend/libs/api/src/lib/generated/index.ts +++ b/frontend/libs/api/src/lib/generated/index.ts @@ -2,59 +2,59 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -export { Client } from './Client'; +export { Client } from "./Client"; -export { ApiError } from './core/ApiError'; -export { BaseHttpRequest } from './core/BaseHttpRequest'; -export { CancelablePromise, CancelError } from './core/CancelablePromise'; -export { OpenAPI } from './core/OpenAPI'; -export type { OpenAPIConfig } from './core/OpenAPI'; +export { ApiError } from "./core/ApiError"; +export { BaseHttpRequest } from "./core/BaseHttpRequest"; +export { CancelablePromise, CancelError } from "./core/CancelablePromise"; +export { OpenAPI } from "./core/OpenAPI"; +export type { OpenAPIConfig } from "./core/OpenAPI"; -export type { AccountType } from './models/AccountType'; -export type { Body_get_token } from './models/Body_get_token'; -export type { ChangeEmailPayload } from './models/ChangeEmailPayload'; -export type { ChangePasswordPayload } from './models/ChangePasswordPayload'; -export type { ClearingAccount } from './models/ClearingAccount'; -export type { ConfirmEmailChangePayload } from './models/ConfirmEmailChangePayload'; -export type { ConfirmPasswordRecoveryPayload } from './models/ConfirmPasswordRecoveryPayload'; -export type { ConfirmRegistrationPayload } from './models/ConfirmRegistrationPayload'; -export type { CreateInvitePayload } from './models/CreateInvitePayload'; -export type { DeleteSessionPayload } from './models/DeleteSessionPayload'; -export type { FileAttachment } from './models/FileAttachment'; -export type { Group } from './models/Group'; -export type { GroupInvite } from './models/GroupInvite'; -export type { GroupLog } from './models/GroupLog'; -export type { GroupMember } from './models/GroupMember'; -export type { GroupMessage } from './models/GroupMessage'; -export type { GroupPayload } from './models/GroupPayload'; -export type { GroupPreview } from './models/GroupPreview'; -export type { HTTPValidationError } from './models/HTTPValidationError'; -export type { LoginPayload } from './models/LoginPayload'; -export type { NewAccount } from './models/NewAccount'; -export type { NewFile } from './models/NewFile'; -export type { NewTransaction } from './models/NewTransaction'; -export type { NewTransactionPosition } from './models/NewTransactionPosition'; -export type { PersonalAccount } from './models/PersonalAccount'; -export type { PreviewGroupPayload } from './models/PreviewGroupPayload'; -export type { RecoverPasswordPayload } from './models/RecoverPasswordPayload'; -export type { RegisterPayload } from './models/RegisterPayload'; -export type { RegisterResponse } from './models/RegisterResponse'; -export type { RenameSessionPayload } from './models/RenameSessionPayload'; -export type { Session } from './models/Session'; -export type { Token } from './models/Token'; -export type { Transaction } from './models/Transaction'; -export type { TransactionPosition } from './models/TransactionPosition'; -export type { TransactionType } from './models/TransactionType'; -export type { UpdateFile } from './models/UpdateFile'; -export type { UpdateGroupMemberPayload } from './models/UpdateGroupMemberPayload'; -export type { UpdatePositionsPayload } from './models/UpdatePositionsPayload'; -export type { UpdateTransaction } from './models/UpdateTransaction'; -export type { User } from './models/User'; -export type { ValidationError } from './models/ValidationError'; -export type { VersionResponse } from './models/VersionResponse'; +export type { AccountType } from "./models/AccountType"; +export type { Body_get_token } from "./models/Body_get_token"; +export type { ChangeEmailPayload } from "./models/ChangeEmailPayload"; +export type { ChangePasswordPayload } from "./models/ChangePasswordPayload"; +export type { ClearingAccount } from "./models/ClearingAccount"; +export type { ConfirmEmailChangePayload } from "./models/ConfirmEmailChangePayload"; +export type { ConfirmPasswordRecoveryPayload } from "./models/ConfirmPasswordRecoveryPayload"; +export type { ConfirmRegistrationPayload } from "./models/ConfirmRegistrationPayload"; +export type { CreateInvitePayload } from "./models/CreateInvitePayload"; +export type { DeleteSessionPayload } from "./models/DeleteSessionPayload"; +export type { FileAttachment } from "./models/FileAttachment"; +export type { Group } from "./models/Group"; +export type { GroupInvite } from "./models/GroupInvite"; +export type { GroupLog } from "./models/GroupLog"; +export type { GroupMember } from "./models/GroupMember"; +export type { GroupMessage } from "./models/GroupMessage"; +export type { GroupPayload } from "./models/GroupPayload"; +export type { GroupPreview } from "./models/GroupPreview"; +export type { HTTPValidationError } from "./models/HTTPValidationError"; +export type { LoginPayload } from "./models/LoginPayload"; +export type { NewAccount } from "./models/NewAccount"; +export type { NewFile } from "./models/NewFile"; +export type { NewTransaction } from "./models/NewTransaction"; +export type { NewTransactionPosition } from "./models/NewTransactionPosition"; +export type { PersonalAccount } from "./models/PersonalAccount"; +export type { PreviewGroupPayload } from "./models/PreviewGroupPayload"; +export type { RecoverPasswordPayload } from "./models/RecoverPasswordPayload"; +export type { RegisterPayload } from "./models/RegisterPayload"; +export type { RegisterResponse } from "./models/RegisterResponse"; +export type { RenameSessionPayload } from "./models/RenameSessionPayload"; +export type { Session } from "./models/Session"; +export type { Token } from "./models/Token"; +export type { Transaction } from "./models/Transaction"; +export type { TransactionPosition } from "./models/TransactionPosition"; +export type { TransactionType } from "./models/TransactionType"; +export type { UpdateFile } from "./models/UpdateFile"; +export type { UpdateGroupMemberPayload } from "./models/UpdateGroupMemberPayload"; +export type { UpdatePositionsPayload } from "./models/UpdatePositionsPayload"; +export type { UpdateTransaction } from "./models/UpdateTransaction"; +export type { User } from "./models/User"; +export type { ValidationError } from "./models/ValidationError"; +export type { VersionResponse } from "./models/VersionResponse"; -export { AccountsService } from './services/AccountsService'; -export { AuthService } from './services/AuthService'; -export { CommonService } from './services/CommonService'; -export { GroupsService } from './services/GroupsService'; -export { TransactionsService } from './services/TransactionsService'; +export { AccountsService } from "./services/AccountsService"; +export { AuthService } from "./services/AuthService"; +export { CommonService } from "./services/CommonService"; +export { GroupsService } from "./services/GroupsService"; +export { TransactionsService } from "./services/TransactionsService"; diff --git a/frontend/libs/api/src/lib/generated/models/AccountType.ts b/frontend/libs/api/src/lib/generated/models/AccountType.ts index 63dd523..0ac44cc 100644 --- a/frontend/libs/api/src/lib/generated/models/AccountType.ts +++ b/frontend/libs/api/src/lib/generated/models/AccountType.ts @@ -2,4 +2,4 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -export type AccountType = 'personal' | 'clearing'; +export type AccountType = "personal" | "clearing"; diff --git a/frontend/libs/api/src/lib/generated/models/Body_get_token.ts b/frontend/libs/api/src/lib/generated/models/Body_get_token.ts index 7ab1d61..3c5cc6d 100644 --- a/frontend/libs/api/src/lib/generated/models/Body_get_token.ts +++ b/frontend/libs/api/src/lib/generated/models/Body_get_token.ts @@ -3,11 +3,10 @@ /* tslint:disable */ /* eslint-disable */ export type Body_get_token = { - grant_type?: (string | null); + grant_type?: string | null; username: string; password: string; scope?: string; - client_id?: (string | null); - client_secret?: (string | null); + client_id?: string | null; + client_secret?: string | null; }; - diff --git a/frontend/libs/api/src/lib/generated/models/ChangeEmailPayload.ts b/frontend/libs/api/src/lib/generated/models/ChangeEmailPayload.ts index 21c9bf3..a30e8ba 100644 --- a/frontend/libs/api/src/lib/generated/models/ChangeEmailPayload.ts +++ b/frontend/libs/api/src/lib/generated/models/ChangeEmailPayload.ts @@ -6,4 +6,3 @@ export type ChangeEmailPayload = { email: string; password: string; }; - diff --git a/frontend/libs/api/src/lib/generated/models/ChangePasswordPayload.ts b/frontend/libs/api/src/lib/generated/models/ChangePasswordPayload.ts index bffab57..3cabe26 100644 --- a/frontend/libs/api/src/lib/generated/models/ChangePasswordPayload.ts +++ b/frontend/libs/api/src/lib/generated/models/ChangePasswordPayload.ts @@ -6,4 +6,3 @@ export type ChangePasswordPayload = { new_password: string; old_password: string; }; - diff --git a/frontend/libs/api/src/lib/generated/models/ClearingAccount.ts b/frontend/libs/api/src/lib/generated/models/ClearingAccount.ts index 21f6739..02d643d 100644 --- a/frontend/libs/api/src/lib/generated/models/ClearingAccount.ts +++ b/frontend/libs/api/src/lib/generated/models/ClearingAccount.ts @@ -14,4 +14,3 @@ export type ClearingAccount = { last_changed: string; deleted: boolean; }; - diff --git a/frontend/libs/api/src/lib/generated/models/ConfirmEmailChangePayload.ts b/frontend/libs/api/src/lib/generated/models/ConfirmEmailChangePayload.ts index ad09f94..b358324 100644 --- a/frontend/libs/api/src/lib/generated/models/ConfirmEmailChangePayload.ts +++ b/frontend/libs/api/src/lib/generated/models/ConfirmEmailChangePayload.ts @@ -5,4 +5,3 @@ export type ConfirmEmailChangePayload = { token: string; }; - diff --git a/frontend/libs/api/src/lib/generated/models/ConfirmPasswordRecoveryPayload.ts b/frontend/libs/api/src/lib/generated/models/ConfirmPasswordRecoveryPayload.ts index 64d4a5c..bddaf8f 100644 --- a/frontend/libs/api/src/lib/generated/models/ConfirmPasswordRecoveryPayload.ts +++ b/frontend/libs/api/src/lib/generated/models/ConfirmPasswordRecoveryPayload.ts @@ -6,4 +6,3 @@ export type ConfirmPasswordRecoveryPayload = { token: string; new_password: string; }; - diff --git a/frontend/libs/api/src/lib/generated/models/ConfirmRegistrationPayload.ts b/frontend/libs/api/src/lib/generated/models/ConfirmRegistrationPayload.ts index 6970d70..f3f810d 100644 --- a/frontend/libs/api/src/lib/generated/models/ConfirmRegistrationPayload.ts +++ b/frontend/libs/api/src/lib/generated/models/ConfirmRegistrationPayload.ts @@ -5,4 +5,3 @@ export type ConfirmRegistrationPayload = { token: string; }; - diff --git a/frontend/libs/api/src/lib/generated/models/CreateInvitePayload.ts b/frontend/libs/api/src/lib/generated/models/CreateInvitePayload.ts index 94d4b11..ed62e6f 100644 --- a/frontend/libs/api/src/lib/generated/models/CreateInvitePayload.ts +++ b/frontend/libs/api/src/lib/generated/models/CreateInvitePayload.ts @@ -8,4 +8,3 @@ export type CreateInvitePayload = { join_as_editor: boolean; valid_until: string; }; - diff --git a/frontend/libs/api/src/lib/generated/models/DeleteSessionPayload.ts b/frontend/libs/api/src/lib/generated/models/DeleteSessionPayload.ts index 34fbafd..0f467af 100644 --- a/frontend/libs/api/src/lib/generated/models/DeleteSessionPayload.ts +++ b/frontend/libs/api/src/lib/generated/models/DeleteSessionPayload.ts @@ -5,4 +5,3 @@ export type DeleteSessionPayload = { session_id: number; }; - diff --git a/frontend/libs/api/src/lib/generated/models/FileAttachment.ts b/frontend/libs/api/src/lib/generated/models/FileAttachment.ts index 15b949a..cf59e5a 100644 --- a/frontend/libs/api/src/lib/generated/models/FileAttachment.ts +++ b/frontend/libs/api/src/lib/generated/models/FileAttachment.ts @@ -5,9 +5,8 @@ export type FileAttachment = { id: number; filename: string; - blob_id: (number | null); - mime_type: (string | null); - host_url?: (string | null); + blob_id: number | null; + mime_type: string | null; + host_url?: string | null; deleted: boolean; }; - diff --git a/frontend/libs/api/src/lib/generated/models/Group.ts b/frontend/libs/api/src/lib/generated/models/Group.ts index 7409c7c..f081524 100644 --- a/frontend/libs/api/src/lib/generated/models/Group.ts +++ b/frontend/libs/api/src/lib/generated/models/Group.ts @@ -14,4 +14,3 @@ export type Group = { last_changed: string; archived: boolean; }; - diff --git a/frontend/libs/api/src/lib/generated/models/GroupInvite.ts b/frontend/libs/api/src/lib/generated/models/GroupInvite.ts index ed8164e..d0eb40f 100644 --- a/frontend/libs/api/src/lib/generated/models/GroupInvite.ts +++ b/frontend/libs/api/src/lib/generated/models/GroupInvite.ts @@ -5,10 +5,9 @@ export type GroupInvite = { id: number; created_by: number; - token: (string | null); + token: string | null; single_use: boolean; join_as_editor: boolean; description: string; valid_until: string; }; - diff --git a/frontend/libs/api/src/lib/generated/models/GroupLog.ts b/frontend/libs/api/src/lib/generated/models/GroupLog.ts index cb6aa8f..9165fae 100644 --- a/frontend/libs/api/src/lib/generated/models/GroupLog.ts +++ b/frontend/libs/api/src/lib/generated/models/GroupLog.ts @@ -8,6 +8,5 @@ export type GroupLog = { logged_at: string; type: string; message: string; - affected: (number | null); + affected: number | null; }; - diff --git a/frontend/libs/api/src/lib/generated/models/GroupMember.ts b/frontend/libs/api/src/lib/generated/models/GroupMember.ts index a982c1d..8ca5547 100644 --- a/frontend/libs/api/src/lib/generated/models/GroupMember.ts +++ b/frontend/libs/api/src/lib/generated/models/GroupMember.ts @@ -9,6 +9,5 @@ export type GroupMember = { can_write: boolean; description: string; joined_at: string; - invited_by: (number | null); + invited_by: number | null; }; - diff --git a/frontend/libs/api/src/lib/generated/models/GroupMessage.ts b/frontend/libs/api/src/lib/generated/models/GroupMessage.ts index 2548d76..7e3e0f7 100644 --- a/frontend/libs/api/src/lib/generated/models/GroupMessage.ts +++ b/frontend/libs/api/src/lib/generated/models/GroupMessage.ts @@ -5,4 +5,3 @@ export type GroupMessage = { message: string; }; - diff --git a/frontend/libs/api/src/lib/generated/models/GroupPayload.ts b/frontend/libs/api/src/lib/generated/models/GroupPayload.ts index f35e3f1..bf67014 100644 --- a/frontend/libs/api/src/lib/generated/models/GroupPayload.ts +++ b/frontend/libs/api/src/lib/generated/models/GroupPayload.ts @@ -9,4 +9,3 @@ export type GroupPayload = { add_user_account_on_join?: boolean; terms?: string; }; - diff --git a/frontend/libs/api/src/lib/generated/models/GroupPreview.ts b/frontend/libs/api/src/lib/generated/models/GroupPreview.ts index 3ce1da7..542f852 100644 --- a/frontend/libs/api/src/lib/generated/models/GroupPreview.ts +++ b/frontend/libs/api/src/lib/generated/models/GroupPreview.ts @@ -13,4 +13,3 @@ export type GroupPreview = { invite_valid_until: string; invite_description: string; }; - diff --git a/frontend/libs/api/src/lib/generated/models/HTTPValidationError.ts b/frontend/libs/api/src/lib/generated/models/HTTPValidationError.ts index f9b1a79..b167d69 100644 --- a/frontend/libs/api/src/lib/generated/models/HTTPValidationError.ts +++ b/frontend/libs/api/src/lib/generated/models/HTTPValidationError.ts @@ -2,8 +2,7 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { ValidationError } from './ValidationError'; +import type { ValidationError } from "./ValidationError"; export type HTTPValidationError = { detail?: Array; }; - diff --git a/frontend/libs/api/src/lib/generated/models/LoginPayload.ts b/frontend/libs/api/src/lib/generated/models/LoginPayload.ts index 035ef4e..bd116b7 100644 --- a/frontend/libs/api/src/lib/generated/models/LoginPayload.ts +++ b/frontend/libs/api/src/lib/generated/models/LoginPayload.ts @@ -7,4 +7,3 @@ export type LoginPayload = { password: string; session_name: string; }; - diff --git a/frontend/libs/api/src/lib/generated/models/NewAccount.ts b/frontend/libs/api/src/lib/generated/models/NewAccount.ts index 146d98d..269eb2e 100644 --- a/frontend/libs/api/src/lib/generated/models/NewAccount.ts +++ b/frontend/libs/api/src/lib/generated/models/NewAccount.ts @@ -2,15 +2,14 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { AccountType } from './AccountType'; +import type { AccountType } from "./AccountType"; export type NewAccount = { type: AccountType; name: string; description?: string; - owning_user_id?: (number | null); - date_info?: (string | null); + owning_user_id?: number | null; + date_info?: string | null; deleted?: boolean; tags?: Array; clearing_shares?: Record; }; - diff --git a/frontend/libs/api/src/lib/generated/models/NewFile.ts b/frontend/libs/api/src/lib/generated/models/NewFile.ts index 53c8afc..ab89d5f 100644 --- a/frontend/libs/api/src/lib/generated/models/NewFile.ts +++ b/frontend/libs/api/src/lib/generated/models/NewFile.ts @@ -7,4 +7,3 @@ export type NewFile = { mime_type: string; content: string; }; - diff --git a/frontend/libs/api/src/lib/generated/models/NewTransaction.ts b/frontend/libs/api/src/lib/generated/models/NewTransaction.ts index ee0e5e2..708ed14 100644 --- a/frontend/libs/api/src/lib/generated/models/NewTransaction.ts +++ b/frontend/libs/api/src/lib/generated/models/NewTransaction.ts @@ -2,9 +2,9 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { NewFile } from './NewFile'; -import type { NewTransactionPosition } from './NewTransactionPosition'; -import type { TransactionType } from './TransactionType'; +import type { NewFile } from "./NewFile"; +import type { NewTransactionPosition } from "./NewTransactionPosition"; +import type { TransactionType } from "./TransactionType"; export type NewTransaction = { type: TransactionType; name: string; @@ -19,4 +19,3 @@ export type NewTransaction = { new_files?: Array; new_positions?: Array; }; - diff --git a/frontend/libs/api/src/lib/generated/models/NewTransactionPosition.ts b/frontend/libs/api/src/lib/generated/models/NewTransactionPosition.ts index 99ad220..9c80676 100644 --- a/frontend/libs/api/src/lib/generated/models/NewTransactionPosition.ts +++ b/frontend/libs/api/src/lib/generated/models/NewTransactionPosition.ts @@ -8,4 +8,3 @@ export type NewTransactionPosition = { communist_shares: number; usages: Record; }; - diff --git a/frontend/libs/api/src/lib/generated/models/PersonalAccount.ts b/frontend/libs/api/src/lib/generated/models/PersonalAccount.ts index 148b7cc..3324c44 100644 --- a/frontend/libs/api/src/lib/generated/models/PersonalAccount.ts +++ b/frontend/libs/api/src/lib/generated/models/PersonalAccount.ts @@ -8,8 +8,7 @@ export type PersonalAccount = { type: "personal"; name: string; description: string; - owning_user_id: (number | null); + owning_user_id: number | null; deleted: boolean; last_changed: string; }; - diff --git a/frontend/libs/api/src/lib/generated/models/PreviewGroupPayload.ts b/frontend/libs/api/src/lib/generated/models/PreviewGroupPayload.ts index a5cb699..97917d4 100644 --- a/frontend/libs/api/src/lib/generated/models/PreviewGroupPayload.ts +++ b/frontend/libs/api/src/lib/generated/models/PreviewGroupPayload.ts @@ -5,4 +5,3 @@ export type PreviewGroupPayload = { invite_token: string; }; - diff --git a/frontend/libs/api/src/lib/generated/models/RecoverPasswordPayload.ts b/frontend/libs/api/src/lib/generated/models/RecoverPasswordPayload.ts index 0ac385d..5067e61 100644 --- a/frontend/libs/api/src/lib/generated/models/RecoverPasswordPayload.ts +++ b/frontend/libs/api/src/lib/generated/models/RecoverPasswordPayload.ts @@ -5,4 +5,3 @@ export type RecoverPasswordPayload = { email: string; }; - diff --git a/frontend/libs/api/src/lib/generated/models/RegisterPayload.ts b/frontend/libs/api/src/lib/generated/models/RegisterPayload.ts index 81ec193..45de331 100644 --- a/frontend/libs/api/src/lib/generated/models/RegisterPayload.ts +++ b/frontend/libs/api/src/lib/generated/models/RegisterPayload.ts @@ -6,6 +6,5 @@ export type RegisterPayload = { username: string; password: string; email: string; - invite_token?: (string | null); + invite_token?: string | null; }; - diff --git a/frontend/libs/api/src/lib/generated/models/RegisterResponse.ts b/frontend/libs/api/src/lib/generated/models/RegisterResponse.ts index 1d6a4e9..fa5499b 100644 --- a/frontend/libs/api/src/lib/generated/models/RegisterResponse.ts +++ b/frontend/libs/api/src/lib/generated/models/RegisterResponse.ts @@ -5,4 +5,3 @@ export type RegisterResponse = { user_id: number; }; - diff --git a/frontend/libs/api/src/lib/generated/models/RenameSessionPayload.ts b/frontend/libs/api/src/lib/generated/models/RenameSessionPayload.ts index 5a3e2a1..51c1ed0 100644 --- a/frontend/libs/api/src/lib/generated/models/RenameSessionPayload.ts +++ b/frontend/libs/api/src/lib/generated/models/RenameSessionPayload.ts @@ -6,4 +6,3 @@ export type RenameSessionPayload = { session_id: number; name: string; }; - diff --git a/frontend/libs/api/src/lib/generated/models/Session.ts b/frontend/libs/api/src/lib/generated/models/Session.ts index 1bb0dea..d3782fa 100644 --- a/frontend/libs/api/src/lib/generated/models/Session.ts +++ b/frontend/libs/api/src/lib/generated/models/Session.ts @@ -5,7 +5,6 @@ export type Session = { id: number; name: string; - valid_until: (string | null); + valid_until: string | null; last_seen: string; }; - diff --git a/frontend/libs/api/src/lib/generated/models/Token.ts b/frontend/libs/api/src/lib/generated/models/Token.ts index e4dcb7c..f04a8f2 100644 --- a/frontend/libs/api/src/lib/generated/models/Token.ts +++ b/frontend/libs/api/src/lib/generated/models/Token.ts @@ -6,4 +6,3 @@ export type Token = { user_id: number; access_token: string; }; - diff --git a/frontend/libs/api/src/lib/generated/models/Transaction.ts b/frontend/libs/api/src/lib/generated/models/Transaction.ts index fd305df..968be7c 100644 --- a/frontend/libs/api/src/lib/generated/models/Transaction.ts +++ b/frontend/libs/api/src/lib/generated/models/Transaction.ts @@ -2,9 +2,9 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { FileAttachment } from './FileAttachment'; -import type { TransactionPosition } from './TransactionPosition'; -import type { TransactionType } from './TransactionType'; +import type { FileAttachment } from "./FileAttachment"; +import type { TransactionPosition } from "./TransactionPosition"; +import type { TransactionType } from "./TransactionType"; export type Transaction = { id: number; group_id: number; @@ -23,4 +23,3 @@ export type Transaction = { positions: Array; files: Array; }; - diff --git a/frontend/libs/api/src/lib/generated/models/TransactionPosition.ts b/frontend/libs/api/src/lib/generated/models/TransactionPosition.ts index d63eacf..19de25d 100644 --- a/frontend/libs/api/src/lib/generated/models/TransactionPosition.ts +++ b/frontend/libs/api/src/lib/generated/models/TransactionPosition.ts @@ -10,4 +10,3 @@ export type TransactionPosition = { id: number; deleted: boolean; }; - diff --git a/frontend/libs/api/src/lib/generated/models/TransactionType.ts b/frontend/libs/api/src/lib/generated/models/TransactionType.ts index 53631cd..092320b 100644 --- a/frontend/libs/api/src/lib/generated/models/TransactionType.ts +++ b/frontend/libs/api/src/lib/generated/models/TransactionType.ts @@ -2,4 +2,4 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -export type TransactionType = 'mimo' | 'purchase' | 'transfer'; +export type TransactionType = "mimo" | "purchase" | "transfer"; diff --git a/frontend/libs/api/src/lib/generated/models/UpdateFile.ts b/frontend/libs/api/src/lib/generated/models/UpdateFile.ts index 226ff3a..9051046 100644 --- a/frontend/libs/api/src/lib/generated/models/UpdateFile.ts +++ b/frontend/libs/api/src/lib/generated/models/UpdateFile.ts @@ -7,4 +7,3 @@ export type UpdateFile = { filename: string; deleted: boolean; }; - diff --git a/frontend/libs/api/src/lib/generated/models/UpdateGroupMemberPayload.ts b/frontend/libs/api/src/lib/generated/models/UpdateGroupMemberPayload.ts index ff21e66..975f60e 100644 --- a/frontend/libs/api/src/lib/generated/models/UpdateGroupMemberPayload.ts +++ b/frontend/libs/api/src/lib/generated/models/UpdateGroupMemberPayload.ts @@ -7,4 +7,3 @@ export type UpdateGroupMemberPayload = { can_write: boolean; is_owner: boolean; }; - diff --git a/frontend/libs/api/src/lib/generated/models/UpdatePositionsPayload.ts b/frontend/libs/api/src/lib/generated/models/UpdatePositionsPayload.ts index f53a37f..693790c 100644 --- a/frontend/libs/api/src/lib/generated/models/UpdatePositionsPayload.ts +++ b/frontend/libs/api/src/lib/generated/models/UpdatePositionsPayload.ts @@ -2,8 +2,7 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { TransactionPosition } from './TransactionPosition'; +import type { TransactionPosition } from "./TransactionPosition"; export type UpdatePositionsPayload = { positions: Array; }; - diff --git a/frontend/libs/api/src/lib/generated/models/UpdateTransaction.ts b/frontend/libs/api/src/lib/generated/models/UpdateTransaction.ts index e5cb822..1ad82ef 100644 --- a/frontend/libs/api/src/lib/generated/models/UpdateTransaction.ts +++ b/frontend/libs/api/src/lib/generated/models/UpdateTransaction.ts @@ -2,11 +2,11 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { NewFile } from './NewFile'; -import type { NewTransactionPosition } from './NewTransactionPosition'; -import type { TransactionPosition } from './TransactionPosition'; -import type { TransactionType } from './TransactionType'; -import type { UpdateFile } from './UpdateFile'; +import type { NewFile } from "./NewFile"; +import type { NewTransactionPosition } from "./NewTransactionPosition"; +import type { TransactionPosition } from "./TransactionPosition"; +import type { TransactionType } from "./TransactionType"; +import type { UpdateFile } from "./UpdateFile"; export type UpdateTransaction = { type: TransactionType; name: string; @@ -23,4 +23,3 @@ export type UpdateTransaction = { changed_files?: Array; changed_positions?: Array; }; - diff --git a/frontend/libs/api/src/lib/generated/models/User.ts b/frontend/libs/api/src/lib/generated/models/User.ts index 31df3aa..34a2b04 100644 --- a/frontend/libs/api/src/lib/generated/models/User.ts +++ b/frontend/libs/api/src/lib/generated/models/User.ts @@ -2,7 +2,7 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { Session } from './Session'; +import type { Session } from "./Session"; export type User = { id: number; username: string; @@ -13,4 +13,3 @@ export type User = { sessions: Array; is_guest_user: boolean; }; - diff --git a/frontend/libs/api/src/lib/generated/models/ValidationError.ts b/frontend/libs/api/src/lib/generated/models/ValidationError.ts index aaf1c92..64d6a72 100644 --- a/frontend/libs/api/src/lib/generated/models/ValidationError.ts +++ b/frontend/libs/api/src/lib/generated/models/ValidationError.ts @@ -3,8 +3,7 @@ /* tslint:disable */ /* eslint-disable */ export type ValidationError = { - loc: Array<(string | number)>; + loc: Array; msg: string; type: string; }; - diff --git a/frontend/libs/api/src/lib/generated/models/VersionResponse.ts b/frontend/libs/api/src/lib/generated/models/VersionResponse.ts index 7e1ba3d..3647645 100644 --- a/frontend/libs/api/src/lib/generated/models/VersionResponse.ts +++ b/frontend/libs/api/src/lib/generated/models/VersionResponse.ts @@ -8,4 +8,3 @@ export type VersionResponse = { minor_version: number; patch_version: number; }; - diff --git a/frontend/libs/api/src/lib/generated/schema.ts b/frontend/libs/api/src/lib/generated/schema.ts index a866219..732c6e7 100644 --- a/frontend/libs/api/src/lib/generated/schema.ts +++ b/frontend/libs/api/src/lib/generated/schema.ts @@ -6,1573 +6,1587 @@ * Do not make direct changes to the file. */ - -import { z } from 'zod'; +import { z } from "zod"; export namespace components.schemas { - /** - * AccountType - * @enum {string} - */ - export const AccountType = z.enum(["personal", "clearing"]); - /** Body_get_token */ - export const Body_get_token = z.object({ - grant_type: z.union([z.string(), z.null()]).optional(), - username: z.string(), - password: z.string(), - scope: z.string().optional(), - client_id: z.union([z.string(), z.null()]).optional(), - client_secret: z.union([z.string(), z.null()]).optional(), - }); - /** ChangeEmailPayload */ - export const ChangeEmailPayload = z.object({ - email: z.string(), - password: z.string(), - }); - /** ChangePasswordPayload */ - export const ChangePasswordPayload = z.object({ - new_password: z.string(), - old_password: z.string(), - }); - /** ClearingAccount */ - export const ClearingAccount = z.object({ - id: z.number().int(), - group_id: z.number().int(), - type: z.literal("clearing"), - name: z.string(), - description: z.string(), - date_info: z.string(), - tags: z.array(z.string()), - clearing_shares: z.record(z.number()), - last_changed: z.string(), - deleted: z.boolean(), - }); - /** ConfirmEmailChangePayload */ - export const ConfirmEmailChangePayload = z.object({ - token: z.string(), - }); - /** ConfirmPasswordRecoveryPayload */ - export const ConfirmPasswordRecoveryPayload = z.object({ - token: z.string(), - new_password: z.string(), - }); - /** ConfirmRegistrationPayload */ - export const ConfirmRegistrationPayload = z.object({ - token: z.string(), - }); - /** CreateInvitePayload */ - export const CreateInvitePayload = z.object({ - description: z.string(), - single_use: z.boolean(), - join_as_editor: z.boolean(), - valid_until: z.string(), - }); - /** DeleteSessionPayload */ - export const DeleteSessionPayload = z.object({ - session_id: z.number().int(), - }); - /** FileAttachment */ - export const FileAttachment = z.object({ - id: z.number().int(), - filename: z.string(), - blob_id: z.union([z.number().int(), z.null()]), - mime_type: z.union([z.string(), z.null()]), - host_url: z.union([z.string(), z.null()]).optional(), - deleted: z.boolean(), - }); - /** Group */ - export const Group = z.object({ - id: z.number().int(), - name: z.string(), - description: z.string(), - currency_symbol: z.string(), - terms: z.string(), - add_user_account_on_join: z.boolean(), - created_at: z.string(), - created_by: z.number().int(), - last_changed: z.string(), - archived: z.boolean(), - }); - /** GroupInvite */ - export const GroupInvite = z.object({ - id: z.number().int(), - created_by: z.number().int(), - token: z.union([z.string(), z.null()]), - single_use: z.boolean(), - join_as_editor: z.boolean(), - description: z.string(), - valid_until: z.string(), - }); - /** GroupLog */ - export const GroupLog = z.object({ - id: z.number().int(), - user_id: z.number().int(), - logged_at: z.string(), - type: z.string(), - message: z.string(), - affected: z.union([z.number().int(), z.null()]), - }); - /** GroupMember */ - export const GroupMember = z.object({ - user_id: z.number().int(), - username: z.string(), - is_owner: z.boolean(), - can_write: z.boolean(), - description: z.string(), - joined_at: z.string(), - invited_by: z.union([z.number().int(), z.null()]), - }); - /** GroupMessage */ - export const GroupMessage = z.object({ - message: z.string(), - }); - /** GroupPayload */ - export const GroupPayload = z.object({ - name: z.string(), - description: z.string().optional(), - currency_symbol: z.string(), - add_user_account_on_join: z.boolean().optional(), - terms: z.string().optional(), - }); - /** GroupPreview */ - export const GroupPreview = z.object({ - id: z.number().int(), - name: z.string(), - description: z.string(), - currency_symbol: z.string(), - terms: z.string(), - created_at: z.string(), - invite_single_use: z.boolean(), - invite_valid_until: z.string(), - invite_description: z.string(), - }); - /** HTTPValidationError */ - export const HTTPValidationError = z.object({ - detail: z.array(components["schemas"]["ValidationError"]).optional(), - }); - /** LoginPayload */ - export const LoginPayload = z.object({ - username: z.string(), - password: z.string(), - session_name: z.string(), - }); - /** NewAccount */ - export const NewAccount = z.object({ - type: components["schemas"]["AccountType"], - name: z.string(), - description: z.string().optional(), - owning_user_id: z.union([z.number().int(), z.null()]).optional(), - date_info: z.union([z.string(), z.null()]).optional(), - deleted: z.boolean().optional(), - tags: z.array(z.string()).optional(), - clearing_shares: z.record(z.number()).optional(), - }); - /** NewFile */ - export const NewFile = z.object({ - filename: z.string(), - mime_type: z.string(), - content: z.string(), - }); - /** NewTransaction */ - export const NewTransaction = z.object({ - type: components["schemas"]["TransactionType"], - name: z.string(), - description: z.string(), - value: z.number(), - currency_symbol: z.string(), - currency_conversion_rate: z.number(), - billed_at: z.string(), - tags: z.array(z.string()).optional(), - creditor_shares: z.record(z.number()), - debitor_shares: z.record(z.number()), - new_files: z.array(components["schemas"]["NewFile"]).optional(), - new_positions: z.array(components["schemas"]["NewTransactionPosition"]).optional(), - }); - /** NewTransactionPosition */ - export const NewTransactionPosition = z.object({ - name: z.string(), - price: z.number(), - communist_shares: z.number(), - usages: z.record(z.number()), - }); - /** PersonalAccount */ - export const PersonalAccount = z.object({ - id: z.number().int(), - group_id: z.number().int(), - type: z.literal("personal"), - name: z.string(), - description: z.string(), - owning_user_id: z.union([z.number().int(), z.null()]), - deleted: z.boolean(), - last_changed: z.string(), - }); - /** PreviewGroupPayload */ - export const PreviewGroupPayload = z.object({ - invite_token: z.string(), - }); - /** RecoverPasswordPayload */ - export const RecoverPasswordPayload = z.object({ - email: z.string(), - }); - /** RegisterPayload */ - export const RegisterPayload = z.object({ - username: z.string(), - password: z.string(), - email: z.string(), - invite_token: z.union([z.string(), z.null()]).optional(), - }); - /** RegisterResponse */ - export const RegisterResponse = z.object({ - user_id: z.number().int(), - }); - /** RenameSessionPayload */ - export const RenameSessionPayload = z.object({ - session_id: z.number().int(), - name: z.string(), - }); - /** Session */ - export const Session = z.object({ - id: z.number().int(), - name: z.string(), - valid_until: z.union([z.string(), z.null()]), - last_seen: z.string(), - }); - /** Token */ - export const Token = z.object({ - user_id: z.number().int(), - access_token: z.string(), - }); - /** Transaction */ - export const Transaction = z.object({ - id: z.number().int(), - group_id: z.number().int(), - type: components["schemas"]["TransactionType"], - name: z.string(), - description: z.string(), - value: z.number(), - currency_symbol: z.string(), - currency_conversion_rate: z.number(), - billed_at: z.string(), - tags: z.array(z.string()), - deleted: z.boolean(), - creditor_shares: z.record(z.number()), - debitor_shares: z.record(z.number()), - last_changed: z.string(), - positions: z.array(components["schemas"]["TransactionPosition"]), - files: z.array(components["schemas"]["FileAttachment"]), - }); - /** TransactionPosition */ - export const TransactionPosition = z.object({ - name: z.string(), - price: z.number(), - communist_shares: z.number(), - usages: z.record(z.number()), - id: z.number().int(), - deleted: z.boolean(), - }); - /** - * TransactionType - * @enum {string} - */ - export const TransactionType = z.enum(["mimo", "purchase", "transfer"]); - /** UpdateFile */ - export const UpdateFile = z.object({ - id: z.number().int(), - filename: z.string(), - deleted: z.boolean(), - }); - /** UpdateGroupMemberPayload */ - export const UpdateGroupMemberPayload = z.object({ - user_id: z.number().int(), - can_write: z.boolean(), - is_owner: z.boolean(), - }); - /** UpdatePositionsPayload */ - export const UpdatePositionsPayload = z.object({ - positions: z.array(components["schemas"]["TransactionPosition"]), - }); - /** UpdateTransaction */ - export const UpdateTransaction = z.object({ - type: components["schemas"]["TransactionType"], - name: z.string(), - description: z.string(), - value: z.number(), - currency_symbol: z.string(), - currency_conversion_rate: z.number(), - billed_at: z.string(), - tags: z.array(z.string()).optional(), - creditor_shares: z.record(z.number()), - debitor_shares: z.record(z.number()), - new_files: z.array(components["schemas"]["NewFile"]).optional(), - new_positions: z.array(components["schemas"]["NewTransactionPosition"]).optional(), - changed_files: z.array(components["schemas"]["UpdateFile"]).optional(), - changed_positions: z.array(components["schemas"]["TransactionPosition"]).optional(), - }); - /** User */ - export const User = z.object({ - id: z.number().int(), - username: z.string(), - email: z.string(), - registered_at: z.string(), - deleted: z.boolean(), - pending: z.boolean(), - sessions: z.array(components["schemas"]["Session"]), - is_guest_user: z.boolean(), - }); - /** ValidationError */ - export const ValidationError = z.object({ - loc: z.array(z.union([z.string(), z.number().int()])), - msg: z.string(), - type: z.string(), - }); - /** - * VersionResponse - * @example { - * "major_version": 1, - * "minor_version": 3, - * "patch_version": 2, - * "version": "1.3.2" - * } - */ - export const VersionResponse = z.object({ - version: z.string(), - major_version: z.number().int(), - minor_version: z.number().int(), - patch_version: z.number().int(), - }); -} - -export const operations = { - - list_transactions: { - /** list all transactions in a group */ - parameters: { - query: z.object({ - min_last_changed: z.union([z.string(), z.null()]).optional(), - transaction_ids: z.union([z.string(), z.null()]).optional(), - }).optional(), - path: z.object({ - group_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": z.array(components["schemas"]["Transaction"]), - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - create_transaction: { - /** create a new transaction */ - parameters: { - path: z.object({ - group_id: z.number().int(), - }), - }, - requestBody: { - content: { - "application/json": components["schemas"]["NewTransaction"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["Transaction"], - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - get_transaction: { - /** get transaction details */ - parameters: { - path: z.object({ - group_id: z.number().int(), - transaction_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["Transaction"], - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - update_transaction: { - /** update transaction details */ - parameters: { - path: z.object({ - group_id: z.number().int(), - transaction_id: z.number().int(), - }), - }, - requestBody: { - content: { - "application/json": components["schemas"]["UpdateTransaction"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["Transaction"], - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - delete_transaction: { - /** delete a transaction */ - parameters: { - path: z.object({ - group_id: z.number().int(), - transaction_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["Transaction"], - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - update_transaction_positions: { - /** update transaction positions */ - parameters: { - path: z.object({ - group_id: z.number().int(), - transaction_id: z.number().int(), - }), - }, - requestBody: { - content: { - "application/json": components["schemas"]["UpdatePositionsPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["Transaction"], - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - get_file_contents: { - /** fetch the (binary) contents of a transaction attachment */ - parameters: { - path: z.object({ - file_id: z.number().int(), - blob_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 200: z.never(), - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - preview_group: { - /** preview a group before joining using an invite token */ - requestBody: { - content: { - "application/json": components["schemas"]["PreviewGroupPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["GroupPreview"], - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - join_group: { - /** join a group using an invite token */ - requestBody: { - content: { - "application/json": components["schemas"]["PreviewGroupPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["Group"], - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - list_groups: { - /** list the current users groups */ - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": z.array(components["schemas"]["Group"]), - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - }, - }, - create_group: { - /** create a group */ - requestBody: { - content: { - "application/json": components["schemas"]["GroupPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["Group"], - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - get_group: { - /** fetch group details */ - parameters: { - path: z.object({ - group_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["Group"], - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - update_group: { - /** update group details */ - parameters: { - path: z.object({ - group_id: z.number().int(), - }), - }, - requestBody: { - content: { - "application/json": components["schemas"]["GroupPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["Group"], - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - delete_group: { - /** delete a group */ - parameters: { - path: z.object({ - group_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 204: z.never(), - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - leave_group: { - /** leave a group */ - parameters: { - path: z.object({ - group_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 204: z.never(), - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - list_members: { - /** list all members of a group */ - parameters: { - path: z.object({ + /** + * AccountType + * @enum {string} + */ + export const AccountType = z.enum(["personal", "clearing"]); + /** Body_get_token */ + export const Body_get_token = z.object({ + grant_type: z.union([z.string(), z.null()]).optional(), + username: z.string(), + password: z.string(), + scope: z.string().optional(), + client_id: z.union([z.string(), z.null()]).optional(), + client_secret: z.union([z.string(), z.null()]).optional(), + }); + /** ChangeEmailPayload */ + export const ChangeEmailPayload = z.object({ + email: z.string(), + password: z.string(), + }); + /** ChangePasswordPayload */ + export const ChangePasswordPayload = z.object({ + new_password: z.string(), + old_password: z.string(), + }); + /** ClearingAccount */ + export const ClearingAccount = z.object({ + id: z.number().int(), group_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": z.array(components["schemas"]["GroupMember"]), - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - update_member_permissions: { - /** update the permissions of a group member */ - parameters: { - path: z.object({ + type: z.literal("clearing"), + name: z.string(), + description: z.string(), + date_info: z.string(), + tags: z.array(z.string()), + clearing_shares: z.record(z.number()), + last_changed: z.string(), + deleted: z.boolean(), + }); + /** ConfirmEmailChangePayload */ + export const ConfirmEmailChangePayload = z.object({ + token: z.string(), + }); + /** ConfirmPasswordRecoveryPayload */ + export const ConfirmPasswordRecoveryPayload = z.object({ + token: z.string(), + new_password: z.string(), + }); + /** ConfirmRegistrationPayload */ + export const ConfirmRegistrationPayload = z.object({ + token: z.string(), + }); + /** CreateInvitePayload */ + export const CreateInvitePayload = z.object({ + description: z.string(), + single_use: z.boolean(), + join_as_editor: z.boolean(), + valid_until: z.string(), + }); + /** DeleteSessionPayload */ + export const DeleteSessionPayload = z.object({ + session_id: z.number().int(), + }); + /** FileAttachment */ + export const FileAttachment = z.object({ + id: z.number().int(), + filename: z.string(), + blob_id: z.union([z.number().int(), z.null()]), + mime_type: z.union([z.string(), z.null()]), + host_url: z.union([z.string(), z.null()]).optional(), + deleted: z.boolean(), + }); + /** Group */ + export const Group = z.object({ + id: z.number().int(), + name: z.string(), + description: z.string(), + currency_symbol: z.string(), + terms: z.string(), + add_user_account_on_join: z.boolean(), + created_at: z.string(), + created_by: z.number().int(), + last_changed: z.string(), + archived: z.boolean(), + }); + /** GroupInvite */ + export const GroupInvite = z.object({ + id: z.number().int(), + created_by: z.number().int(), + token: z.union([z.string(), z.null()]), + single_use: z.boolean(), + join_as_editor: z.boolean(), + description: z.string(), + valid_until: z.string(), + }); + /** GroupLog */ + export const GroupLog = z.object({ + id: z.number().int(), + user_id: z.number().int(), + logged_at: z.string(), + type: z.string(), + message: z.string(), + affected: z.union([z.number().int(), z.null()]), + }); + /** GroupMember */ + export const GroupMember = z.object({ + user_id: z.number().int(), + username: z.string(), + is_owner: z.boolean(), + can_write: z.boolean(), + description: z.string(), + joined_at: z.string(), + invited_by: z.union([z.number().int(), z.null()]), + }); + /** GroupMessage */ + export const GroupMessage = z.object({ + message: z.string(), + }); + /** GroupPayload */ + export const GroupPayload = z.object({ + name: z.string(), + description: z.string().optional(), + currency_symbol: z.string(), + add_user_account_on_join: z.boolean().optional(), + terms: z.string().optional(), + }); + /** GroupPreview */ + export const GroupPreview = z.object({ + id: z.number().int(), + name: z.string(), + description: z.string(), + currency_symbol: z.string(), + terms: z.string(), + created_at: z.string(), + invite_single_use: z.boolean(), + invite_valid_until: z.string(), + invite_description: z.string(), + }); + /** HTTPValidationError */ + export const HTTPValidationError = z.object({ + detail: z.array(components["schemas"]["ValidationError"]).optional(), + }); + /** LoginPayload */ + export const LoginPayload = z.object({ + username: z.string(), + password: z.string(), + session_name: z.string(), + }); + /** NewAccount */ + export const NewAccount = z.object({ + type: components["schemas"]["AccountType"], + name: z.string(), + description: z.string().optional(), + owning_user_id: z.union([z.number().int(), z.null()]).optional(), + date_info: z.union([z.string(), z.null()]).optional(), + deleted: z.boolean().optional(), + tags: z.array(z.string()).optional(), + clearing_shares: z.record(z.number()).optional(), + }); + /** NewFile */ + export const NewFile = z.object({ + filename: z.string(), + mime_type: z.string(), + content: z.string(), + }); + /** NewTransaction */ + export const NewTransaction = z.object({ + type: components["schemas"]["TransactionType"], + name: z.string(), + description: z.string(), + value: z.number(), + currency_symbol: z.string(), + currency_conversion_rate: z.number(), + billed_at: z.string(), + tags: z.array(z.string()).optional(), + creditor_shares: z.record(z.number()), + debitor_shares: z.record(z.number()), + new_files: z.array(components["schemas"]["NewFile"]).optional(), + new_positions: z.array(components["schemas"]["NewTransactionPosition"]).optional(), + }); + /** NewTransactionPosition */ + export const NewTransactionPosition = z.object({ + name: z.string(), + price: z.number(), + communist_shares: z.number(), + usages: z.record(z.number()), + }); + /** PersonalAccount */ + export const PersonalAccount = z.object({ + id: z.number().int(), group_id: z.number().int(), - }), - }, - requestBody: { - content: { - "application/json": components["schemas"]["UpdateGroupMemberPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["GroupMember"], - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - list_log: { - /** fetch the group log */ - parameters: { - path: z.object({ + type: z.literal("personal"), + name: z.string(), + description: z.string(), + owning_user_id: z.union([z.number().int(), z.null()]), + deleted: z.boolean(), + last_changed: z.string(), + }); + /** PreviewGroupPayload */ + export const PreviewGroupPayload = z.object({ + invite_token: z.string(), + }); + /** RecoverPasswordPayload */ + export const RecoverPasswordPayload = z.object({ + email: z.string(), + }); + /** RegisterPayload */ + export const RegisterPayload = z.object({ + username: z.string(), + password: z.string(), + email: z.string(), + invite_token: z.union([z.string(), z.null()]).optional(), + }); + /** RegisterResponse */ + export const RegisterResponse = z.object({ + user_id: z.number().int(), + }); + /** RenameSessionPayload */ + export const RenameSessionPayload = z.object({ + session_id: z.number().int(), + name: z.string(), + }); + /** Session */ + export const Session = z.object({ + id: z.number().int(), + name: z.string(), + valid_until: z.union([z.string(), z.null()]), + last_seen: z.string(), + }); + /** Token */ + export const Token = z.object({ + user_id: z.number().int(), + access_token: z.string(), + }); + /** Transaction */ + export const Transaction = z.object({ + id: z.number().int(), group_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": z.array(components["schemas"]["GroupLog"]), - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - send_group_message: { - /** post a message to the group log */ - parameters: { - path: z.object({ - group_id: z.number().int(), - }), - }, - requestBody: { - content: { - "application/json": components["schemas"]["GroupMessage"], - }, - }, - responses: { - /** @description Successful Response */ - 204: z.never(), - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - list_invites: { - /** list all invite links of a group */ - parameters: { - path: z.object({ - group_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": z.array(components["schemas"]["GroupInvite"]), - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - create_invite: { - /** create a new group invite link */ - parameters: { - path: z.object({ - group_id: z.number().int(), - }), - }, - requestBody: { - content: { - "application/json": components["schemas"]["CreateInvitePayload"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["GroupInvite"], - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - delete_invite: { - /** delete a group invite link */ - parameters: { - path: z.object({ - group_id: z.number().int(), - invite_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 204: z.never(), - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - archive_group: { - /** archive a group */ - parameters: { - path: z.object({ - group_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": z.record(z.any()), - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - unarchive_group: { - /** un-archive a group */ - parameters: { - path: z.object({ - group_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": z.record(z.any()), - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - get_token: { - /** login with username and password */ - requestBody: { - content: { - "application/x-www-form-urlencoded": components["schemas"]["Body_get_token"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["Token"], - }, - }, - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - login: { - /** login with username and password */ - requestBody: { - content: { - "application/json": components["schemas"]["LoginPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["Token"], - }, - }, - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - logout: { - /** sign out of the current session */ - responses: { - /** @description Successful Response */ - 204: z.never(), - }, - }, - register: { - /** register a new user */ - requestBody: { - content: { - "application/json": components["schemas"]["RegisterPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["RegisterResponse"], - }, - }, - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - confirm_registration: { - /** confirm a pending registration */ - requestBody: { - content: { - "application/json": components["schemas"]["ConfirmRegistrationPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 204: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - get_profile: { - /** fetch user profile information */ - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["User"], - }, - }, - }, - }, - change_password: { - /** change password */ - requestBody: { - content: { - "application/json": components["schemas"]["ChangePasswordPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 204: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - change_email: { - /** change email */ - requestBody: { - content: { - "application/json": components["schemas"]["ChangeEmailPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 204: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - confirm_email_change: { - /** confirm a pending email change */ - requestBody: { - content: { - "application/json": components["schemas"]["ConfirmEmailChangePayload"], - }, - }, - responses: { - /** @description Successful Response */ - 204: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - recover_password: { - /** recover password */ - requestBody: { - content: { - "application/json": components["schemas"]["RecoverPasswordPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 204: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - confirm_password_recovery: { - /** confirm a pending password recovery */ - requestBody: { - content: { - "application/json": components["schemas"]["ConfirmPasswordRecoveryPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 204: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - delete_session: { - /** delete a given user session */ - requestBody: { - content: { - "application/json": components["schemas"]["DeleteSessionPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 204: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - rename_session: { - /** rename a given user session */ - requestBody: { - content: { - "application/json": components["schemas"]["RenameSessionPayload"], - }, - }, - responses: { - /** @description Successful Response */ - 204: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - list_accounts: { - /** list all accounts in a group */ - parameters: { - path: z.object({ - group_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": z.array(z.union([components["schemas"]["ClearingAccount"], components["schemas"]["PersonalAccount"]])), - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - create_account: { - /** create a new group account */ - parameters: { - path: z.object({ - group_id: z.number().int(), - }), - }, - requestBody: { - content: { - "application/json": components["schemas"]["NewAccount"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": z.union([components["schemas"]["ClearingAccount"], components["schemas"]["PersonalAccount"]]), - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - get_account: { - /** fetch a group account */ - parameters: { - path: z.object({ - group_id: z.number().int(), - account_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": z.union([components["schemas"]["ClearingAccount"], components["schemas"]["PersonalAccount"]]), - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - update_account: { - /** update an account */ - parameters: { - path: z.object({ - group_id: z.number().int(), - account_id: z.number().int(), - }), - }, - requestBody: { - content: { - "application/json": components["schemas"]["NewAccount"], - }, - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": z.union([components["schemas"]["ClearingAccount"], components["schemas"]["PersonalAccount"]]), - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - delete_account: { - /** delete an account */ - parameters: { - path: z.object({ - group_id: z.number().int(), - account_id: z.number().int(), - }), - }, - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": z.union([components["schemas"]["ClearingAccount"], components["schemas"]["PersonalAccount"]]), - }, - }, - /** @description unauthorized */ - 401: z.never(), - /** @description forbidden */ - 403: z.never(), - /** @description Not found */ - 404: z.never(), - /** @description Validation Error */ - 422: { - content: { - "application/json": components["schemas"]["HTTPValidationError"], - }, - }, - }, - }, - get_version: { - /** Get Version */ - responses: { - /** @description Successful Response */ - 200: { - content: { - "application/json": components["schemas"]["VersionResponse"], - }, - }, - }, - }, + type: components["schemas"]["TransactionType"], + name: z.string(), + description: z.string(), + value: z.number(), + currency_symbol: z.string(), + currency_conversion_rate: z.number(), + billed_at: z.string(), + tags: z.array(z.string()), + deleted: z.boolean(), + creditor_shares: z.record(z.number()), + debitor_shares: z.record(z.number()), + last_changed: z.string(), + positions: z.array(components["schemas"]["TransactionPosition"]), + files: z.array(components["schemas"]["FileAttachment"]), + }); + /** TransactionPosition */ + export const TransactionPosition = z.object({ + name: z.string(), + price: z.number(), + communist_shares: z.number(), + usages: z.record(z.number()), + id: z.number().int(), + deleted: z.boolean(), + }); + /** + * TransactionType + * @enum {string} + */ + export const TransactionType = z.enum(["mimo", "purchase", "transfer"]); + /** UpdateFile */ + export const UpdateFile = z.object({ + id: z.number().int(), + filename: z.string(), + deleted: z.boolean(), + }); + /** UpdateGroupMemberPayload */ + export const UpdateGroupMemberPayload = z.object({ + user_id: z.number().int(), + can_write: z.boolean(), + is_owner: z.boolean(), + }); + /** UpdatePositionsPayload */ + export const UpdatePositionsPayload = z.object({ + positions: z.array(components["schemas"]["TransactionPosition"]), + }); + /** UpdateTransaction */ + export const UpdateTransaction = z.object({ + type: components["schemas"]["TransactionType"], + name: z.string(), + description: z.string(), + value: z.number(), + currency_symbol: z.string(), + currency_conversion_rate: z.number(), + billed_at: z.string(), + tags: z.array(z.string()).optional(), + creditor_shares: z.record(z.number()), + debitor_shares: z.record(z.number()), + new_files: z.array(components["schemas"]["NewFile"]).optional(), + new_positions: z.array(components["schemas"]["NewTransactionPosition"]).optional(), + changed_files: z.array(components["schemas"]["UpdateFile"]).optional(), + changed_positions: z.array(components["schemas"]["TransactionPosition"]).optional(), + }); + /** User */ + export const User = z.object({ + id: z.number().int(), + username: z.string(), + email: z.string(), + registered_at: z.string(), + deleted: z.boolean(), + pending: z.boolean(), + sessions: z.array(components["schemas"]["Session"]), + is_guest_user: z.boolean(), + }); + /** ValidationError */ + export const ValidationError = z.object({ + loc: z.array(z.union([z.string(), z.number().int()])), + msg: z.string(), + type: z.string(), + }); + /** + * VersionResponse + * @example { + * "major_version": 1, + * "minor_version": 3, + * "patch_version": 2, + * "version": "1.3.2" + * } + */ + export const VersionResponse = z.object({ + version: z.string(), + major_version: z.number().int(), + minor_version: z.number().int(), + patch_version: z.number().int(), + }); } +export const operations = { + list_transactions: { + /** list all transactions in a group */ + parameters: { + query: z + .object({ + min_last_changed: z.union([z.string(), z.null()]).optional(), + transaction_ids: z.union([z.string(), z.null()]).optional(), + }) + .optional(), + path: z.object({ + group_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": z.array(components["schemas"]["Transaction"]), + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + create_transaction: { + /** create a new transaction */ + parameters: { + path: z.object({ + group_id: z.number().int(), + }), + }, + requestBody: { + content: { + "application/json": components["schemas"]["NewTransaction"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["Transaction"], + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + get_transaction: { + /** get transaction details */ + parameters: { + path: z.object({ + group_id: z.number().int(), + transaction_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["Transaction"], + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + update_transaction: { + /** update transaction details */ + parameters: { + path: z.object({ + group_id: z.number().int(), + transaction_id: z.number().int(), + }), + }, + requestBody: { + content: { + "application/json": components["schemas"]["UpdateTransaction"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["Transaction"], + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + delete_transaction: { + /** delete a transaction */ + parameters: { + path: z.object({ + group_id: z.number().int(), + transaction_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["Transaction"], + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + update_transaction_positions: { + /** update transaction positions */ + parameters: { + path: z.object({ + group_id: z.number().int(), + transaction_id: z.number().int(), + }), + }, + requestBody: { + content: { + "application/json": components["schemas"]["UpdatePositionsPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["Transaction"], + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + get_file_contents: { + /** fetch the (binary) contents of a transaction attachment */ + parameters: { + path: z.object({ + file_id: z.number().int(), + blob_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 200: z.never(), + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + preview_group: { + /** preview a group before joining using an invite token */ + requestBody: { + content: { + "application/json": components["schemas"]["PreviewGroupPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["GroupPreview"], + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + join_group: { + /** join a group using an invite token */ + requestBody: { + content: { + "application/json": components["schemas"]["PreviewGroupPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["Group"], + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + list_groups: { + /** list the current users groups */ + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": z.array(components["schemas"]["Group"]), + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + }, + }, + create_group: { + /** create a group */ + requestBody: { + content: { + "application/json": components["schemas"]["GroupPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["Group"], + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + get_group: { + /** fetch group details */ + parameters: { + path: z.object({ + group_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["Group"], + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + update_group: { + /** update group details */ + parameters: { + path: z.object({ + group_id: z.number().int(), + }), + }, + requestBody: { + content: { + "application/json": components["schemas"]["GroupPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["Group"], + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + delete_group: { + /** delete a group */ + parameters: { + path: z.object({ + group_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 204: z.never(), + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + leave_group: { + /** leave a group */ + parameters: { + path: z.object({ + group_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 204: z.never(), + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + list_members: { + /** list all members of a group */ + parameters: { + path: z.object({ + group_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": z.array(components["schemas"]["GroupMember"]), + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + update_member_permissions: { + /** update the permissions of a group member */ + parameters: { + path: z.object({ + group_id: z.number().int(), + }), + }, + requestBody: { + content: { + "application/json": components["schemas"]["UpdateGroupMemberPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["GroupMember"], + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + list_log: { + /** fetch the group log */ + parameters: { + path: z.object({ + group_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": z.array(components["schemas"]["GroupLog"]), + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + send_group_message: { + /** post a message to the group log */ + parameters: { + path: z.object({ + group_id: z.number().int(), + }), + }, + requestBody: { + content: { + "application/json": components["schemas"]["GroupMessage"], + }, + }, + responses: { + /** @description Successful Response */ + 204: z.never(), + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + list_invites: { + /** list all invite links of a group */ + parameters: { + path: z.object({ + group_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": z.array(components["schemas"]["GroupInvite"]), + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + create_invite: { + /** create a new group invite link */ + parameters: { + path: z.object({ + group_id: z.number().int(), + }), + }, + requestBody: { + content: { + "application/json": components["schemas"]["CreateInvitePayload"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["GroupInvite"], + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + delete_invite: { + /** delete a group invite link */ + parameters: { + path: z.object({ + group_id: z.number().int(), + invite_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 204: z.never(), + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + archive_group: { + /** archive a group */ + parameters: { + path: z.object({ + group_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": z.record(z.any()), + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + unarchive_group: { + /** un-archive a group */ + parameters: { + path: z.object({ + group_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": z.record(z.any()), + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + get_token: { + /** login with username and password */ + requestBody: { + content: { + "application/x-www-form-urlencoded": components["schemas"]["Body_get_token"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["Token"], + }, + }, + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + login: { + /** login with username and password */ + requestBody: { + content: { + "application/json": components["schemas"]["LoginPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["Token"], + }, + }, + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + logout: { + /** sign out of the current session */ + responses: { + /** @description Successful Response */ + 204: z.never(), + }, + }, + register: { + /** register a new user */ + requestBody: { + content: { + "application/json": components["schemas"]["RegisterPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["RegisterResponse"], + }, + }, + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + confirm_registration: { + /** confirm a pending registration */ + requestBody: { + content: { + "application/json": components["schemas"]["ConfirmRegistrationPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 204: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + get_profile: { + /** fetch user profile information */ + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["User"], + }, + }, + }, + }, + change_password: { + /** change password */ + requestBody: { + content: { + "application/json": components["schemas"]["ChangePasswordPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 204: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + change_email: { + /** change email */ + requestBody: { + content: { + "application/json": components["schemas"]["ChangeEmailPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 204: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + confirm_email_change: { + /** confirm a pending email change */ + requestBody: { + content: { + "application/json": components["schemas"]["ConfirmEmailChangePayload"], + }, + }, + responses: { + /** @description Successful Response */ + 204: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + recover_password: { + /** recover password */ + requestBody: { + content: { + "application/json": components["schemas"]["RecoverPasswordPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 204: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + confirm_password_recovery: { + /** confirm a pending password recovery */ + requestBody: { + content: { + "application/json": components["schemas"]["ConfirmPasswordRecoveryPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 204: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + delete_session: { + /** delete a given user session */ + requestBody: { + content: { + "application/json": components["schemas"]["DeleteSessionPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 204: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + rename_session: { + /** rename a given user session */ + requestBody: { + content: { + "application/json": components["schemas"]["RenameSessionPayload"], + }, + }, + responses: { + /** @description Successful Response */ + 204: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + list_accounts: { + /** list all accounts in a group */ + parameters: { + path: z.object({ + group_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": z.array( + z.union([components["schemas"]["ClearingAccount"], components["schemas"]["PersonalAccount"]]) + ), + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + create_account: { + /** create a new group account */ + parameters: { + path: z.object({ + group_id: z.number().int(), + }), + }, + requestBody: { + content: { + "application/json": components["schemas"]["NewAccount"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": z.union([ + components["schemas"]["ClearingAccount"], + components["schemas"]["PersonalAccount"], + ]), + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + get_account: { + /** fetch a group account */ + parameters: { + path: z.object({ + group_id: z.number().int(), + account_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": z.union([ + components["schemas"]["ClearingAccount"], + components["schemas"]["PersonalAccount"], + ]), + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + update_account: { + /** update an account */ + parameters: { + path: z.object({ + group_id: z.number().int(), + account_id: z.number().int(), + }), + }, + requestBody: { + content: { + "application/json": components["schemas"]["NewAccount"], + }, + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": z.union([ + components["schemas"]["ClearingAccount"], + components["schemas"]["PersonalAccount"], + ]), + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + delete_account: { + /** delete an account */ + parameters: { + path: z.object({ + group_id: z.number().int(), + account_id: z.number().int(), + }), + }, + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": z.union([ + components["schemas"]["ClearingAccount"], + components["schemas"]["PersonalAccount"], + ]), + }, + }, + /** @description unauthorized */ + 401: z.never(), + /** @description forbidden */ + 403: z.never(), + /** @description Not found */ + 404: z.never(), + /** @description Validation Error */ + 422: { + content: { + "application/json": components["schemas"]["HTTPValidationError"], + }, + }, + }, + }, + get_version: { + /** Get Version */ + responses: { + /** @description Successful Response */ + 200: { + content: { + "application/json": components["schemas"]["VersionResponse"], + }, + }, + }, + }, +}; + export const paths = { - "/api/v1/groups/{group_id}/transactions": { - /** list all transactions in a group */ - get: operations["list_transactions"], - /** create a new transaction */ - post: operations["create_transaction"], - }, - "/api/v1/groups/{group_id}/transactions/{transaction_id}": { - /** get transaction details */ - get: operations["get_transaction"], - /** update transaction details */ - post: operations["update_transaction"], - /** delete a transaction */ - delete: operations["delete_transaction"], - }, - "/api/v1/groups/{group_id}/transactions/{transaction_id}/positions": { - /** update transaction positions */ - post: operations["update_transaction_positions"], - }, - "/api/v1/files/{file_id}/{blob_id}": { - /** fetch the (binary) contents of a transaction attachment */ - get: operations["get_file_contents"], - }, - "/api/v1/groups/preview": { - /** preview a group before joining using an invite token */ - post: operations["preview_group"], - }, - "/api/v1/groups/join": { - /** join a group using an invite token */ - post: operations["join_group"], - }, - "/api/v1/groups": { - /** list the current users groups */ - get: operations["list_groups"], - /** create a group */ - post: operations["create_group"], - }, - "/api/v1/groups/{group_id}": { - /** fetch group details */ - get: operations["get_group"], - /** update group details */ - post: operations["update_group"], - /** delete a group */ - delete: operations["delete_group"], - }, - "/api/v1/groups/{group_id}/leave": { - /** leave a group */ - post: operations["leave_group"], - }, - "/api/v1/groups/{group_id}/members": { - /** list all members of a group */ - get: operations["list_members"], - /** update the permissions of a group member */ - post: operations["update_member_permissions"], - }, - "/api/v1/groups/{group_id}/logs": { - /** fetch the group log */ - get: operations["list_log"], - }, - "/api/v1/groups/{group_id}/send_message": { - /** post a message to the group log */ - post: operations["send_group_message"], - }, - "/api/v1/groups/{group_id}/invites": { - /** list all invite links of a group */ - get: operations["list_invites"], - /** create a new group invite link */ - post: operations["create_invite"], - }, - "/api/v1/groups/{group_id}/invites/{invite_id}": { - /** delete a group invite link */ - delete: operations["delete_invite"], - }, - "/api/v1/groups/{group_id}/archive": { - /** archive a group */ - post: operations["archive_group"], - }, - "/api/v1/groups/{group_id}/un-archive": { - /** un-archive a group */ - post: operations["unarchive_group"], - }, - "/api/v1/auth/token": { - /** login with username and password */ - post: operations["get_token"], - }, - "/api/v1/auth/login": { - /** login with username and password */ - post: operations["login"], - }, - "/api/v1/auth/logout": { - /** sign out of the current session */ - post: operations["logout"], - }, - "/api/v1/auth/register": { - /** register a new user */ - post: operations["register"], - }, - "/api/v1/auth/confirm_registration": { - /** confirm a pending registration */ - post: operations["confirm_registration"], - }, - "/api/v1/profile": { - /** fetch user profile information */ - get: operations["get_profile"], - }, - "/api/v1/profile/change_password": { - /** change password */ - post: operations["change_password"], - }, - "/api/v1/profile/change_email": { - /** change email */ - post: operations["change_email"], - }, - "/api/v1/auth/confirm_email_change": { - /** confirm a pending email change */ - post: operations["confirm_email_change"], - }, - "/api/v1/auth/recover_password": { - /** recover password */ - post: operations["recover_password"], - }, - "/api/v1/auth/confirm_password_recovery": { - /** confirm a pending password recovery */ - post: operations["confirm_password_recovery"], - }, - "/api/v1/auth/delete_session": { - /** delete a given user session */ - post: operations["delete_session"], - }, - "/api/v1/auth/rename_session": { - /** rename a given user session */ - post: operations["rename_session"], - }, - "/api/v1/groups/{group_id}/accounts": { - /** list all accounts in a group */ - get: operations["list_accounts"], - /** create a new group account */ - post: operations["create_account"], - }, - "/api/v1/groups/{group_id}/accounts/{account_id}": { - /** fetch a group account */ - get: operations["get_account"], - /** update an account */ - post: operations["update_account"], - /** delete an account */ - delete: operations["delete_account"], - }, - "/api/version": { - /** Get Version */ - get: operations["get_version"], - }, -} + "/api/v1/groups/{group_id}/transactions": { + /** list all transactions in a group */ + get: operations["list_transactions"], + /** create a new transaction */ + post: operations["create_transaction"], + }, + "/api/v1/groups/{group_id}/transactions/{transaction_id}": { + /** get transaction details */ + get: operations["get_transaction"], + /** update transaction details */ + post: operations["update_transaction"], + /** delete a transaction */ + delete: operations["delete_transaction"], + }, + "/api/v1/groups/{group_id}/transactions/{transaction_id}/positions": { + /** update transaction positions */ + post: operations["update_transaction_positions"], + }, + "/api/v1/files/{file_id}/{blob_id}": { + /** fetch the (binary) contents of a transaction attachment */ + get: operations["get_file_contents"], + }, + "/api/v1/groups/preview": { + /** preview a group before joining using an invite token */ + post: operations["preview_group"], + }, + "/api/v1/groups/join": { + /** join a group using an invite token */ + post: operations["join_group"], + }, + "/api/v1/groups": { + /** list the current users groups */ + get: operations["list_groups"], + /** create a group */ + post: operations["create_group"], + }, + "/api/v1/groups/{group_id}": { + /** fetch group details */ + get: operations["get_group"], + /** update group details */ + post: operations["update_group"], + /** delete a group */ + delete: operations["delete_group"], + }, + "/api/v1/groups/{group_id}/leave": { + /** leave a group */ + post: operations["leave_group"], + }, + "/api/v1/groups/{group_id}/members": { + /** list all members of a group */ + get: operations["list_members"], + /** update the permissions of a group member */ + post: operations["update_member_permissions"], + }, + "/api/v1/groups/{group_id}/logs": { + /** fetch the group log */ + get: operations["list_log"], + }, + "/api/v1/groups/{group_id}/send_message": { + /** post a message to the group log */ + post: operations["send_group_message"], + }, + "/api/v1/groups/{group_id}/invites": { + /** list all invite links of a group */ + get: operations["list_invites"], + /** create a new group invite link */ + post: operations["create_invite"], + }, + "/api/v1/groups/{group_id}/invites/{invite_id}": { + /** delete a group invite link */ + delete: operations["delete_invite"], + }, + "/api/v1/groups/{group_id}/archive": { + /** archive a group */ + post: operations["archive_group"], + }, + "/api/v1/groups/{group_id}/un-archive": { + /** un-archive a group */ + post: operations["unarchive_group"], + }, + "/api/v1/auth/token": { + /** login with username and password */ + post: operations["get_token"], + }, + "/api/v1/auth/login": { + /** login with username and password */ + post: operations["login"], + }, + "/api/v1/auth/logout": { + /** sign out of the current session */ + post: operations["logout"], + }, + "/api/v1/auth/register": { + /** register a new user */ + post: operations["register"], + }, + "/api/v1/auth/confirm_registration": { + /** confirm a pending registration */ + post: operations["confirm_registration"], + }, + "/api/v1/profile": { + /** fetch user profile information */ + get: operations["get_profile"], + }, + "/api/v1/profile/change_password": { + /** change password */ + post: operations["change_password"], + }, + "/api/v1/profile/change_email": { + /** change email */ + post: operations["change_email"], + }, + "/api/v1/auth/confirm_email_change": { + /** confirm a pending email change */ + post: operations["confirm_email_change"], + }, + "/api/v1/auth/recover_password": { + /** recover password */ + post: operations["recover_password"], + }, + "/api/v1/auth/confirm_password_recovery": { + /** confirm a pending password recovery */ + post: operations["confirm_password_recovery"], + }, + "/api/v1/auth/delete_session": { + /** delete a given user session */ + post: operations["delete_session"], + }, + "/api/v1/auth/rename_session": { + /** rename a given user session */ + post: operations["rename_session"], + }, + "/api/v1/groups/{group_id}/accounts": { + /** list all accounts in a group */ + get: operations["list_accounts"], + /** create a new group account */ + post: operations["create_account"], + }, + "/api/v1/groups/{group_id}/accounts/{account_id}": { + /** fetch a group account */ + get: operations["get_account"], + /** update an account */ + post: operations["update_account"], + /** delete an account */ + delete: operations["delete_account"], + }, + "/api/version": { + /** Get Version */ + get: operations["get_version"], + }, +}; diff --git a/frontend/libs/api/src/lib/generated/services/AccountsService.ts b/frontend/libs/api/src/lib/generated/services/AccountsService.ts index 6e5c103..3d639b0 100644 --- a/frontend/libs/api/src/lib/generated/services/AccountsService.ts +++ b/frontend/libs/api/src/lib/generated/services/AccountsService.ts @@ -2,11 +2,11 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { ClearingAccount } from '../models/ClearingAccount'; -import type { NewAccount } from '../models/NewAccount'; -import type { PersonalAccount } from '../models/PersonalAccount'; -import type { CancelablePromise } from '../core/CancelablePromise'; -import type { BaseHttpRequest } from '../core/BaseHttpRequest'; +import type { ClearingAccount } from "../models/ClearingAccount"; +import type { NewAccount } from "../models/NewAccount"; +import type { PersonalAccount } from "../models/PersonalAccount"; +import type { CancelablePromise } from "../core/CancelablePromise"; +import type { BaseHttpRequest } from "../core/BaseHttpRequest"; export class AccountsService { constructor(public readonly httpRequest: BaseHttpRequest) {} /** @@ -14,16 +14,12 @@ export class AccountsService { * @returns any Successful Response * @throws ApiError */ - public listAccounts({ - groupId, - }: { - groupId: number, - }): CancelablePromise> { + public listAccounts({ groupId }: { groupId: number }): CancelablePromise> { return this.httpRequest.request({ - method: 'GET', - url: '/api/v1/groups/{group_id}/accounts', + method: "GET", + url: "/api/v1/groups/{group_id}/accounts", path: { - 'group_id': groupId, + group_id: groupId, }, errors: { 401: `unauthorized`, @@ -42,17 +38,17 @@ export class AccountsService { groupId, requestBody, }: { - groupId: number, - requestBody: NewAccount, - }): CancelablePromise<(ClearingAccount | PersonalAccount)> { + groupId: number; + requestBody: NewAccount; + }): CancelablePromise { return this.httpRequest.request({ - method: 'POST', - url: '/api/v1/groups/{group_id}/accounts', + method: "POST", + url: "/api/v1/groups/{group_id}/accounts", path: { - 'group_id': groupId, + group_id: groupId, }, body: requestBody, - mediaType: 'application/json', + mediaType: "application/json", errors: { 401: `unauthorized`, 403: `forbidden`, @@ -70,15 +66,15 @@ export class AccountsService { groupId, accountId, }: { - groupId: number, - accountId: number, - }): CancelablePromise<(ClearingAccount | PersonalAccount)> { + groupId: number; + accountId: number; + }): CancelablePromise { return this.httpRequest.request({ - method: 'GET', - url: '/api/v1/groups/{group_id}/accounts/{account_id}', + method: "GET", + url: "/api/v1/groups/{group_id}/accounts/{account_id}", path: { - 'group_id': groupId, - 'account_id': accountId, + group_id: groupId, + account_id: accountId, }, errors: { 401: `unauthorized`, @@ -98,19 +94,19 @@ export class AccountsService { accountId, requestBody, }: { - groupId: number, - accountId: number, - requestBody: NewAccount, - }): CancelablePromise<(ClearingAccount | PersonalAccount)> { + groupId: number; + accountId: number; + requestBody: NewAccount; + }): CancelablePromise { return this.httpRequest.request({ - method: 'POST', - url: '/api/v1/groups/{group_id}/accounts/{account_id}', + method: "POST", + url: "/api/v1/groups/{group_id}/accounts/{account_id}", path: { - 'group_id': groupId, - 'account_id': accountId, + group_id: groupId, + account_id: accountId, }, body: requestBody, - mediaType: 'application/json', + mediaType: "application/json", errors: { 401: `unauthorized`, 403: `forbidden`, @@ -128,15 +124,15 @@ export class AccountsService { groupId, accountId, }: { - groupId: number, - accountId: number, - }): CancelablePromise<(ClearingAccount | PersonalAccount)> { + groupId: number; + accountId: number; + }): CancelablePromise { return this.httpRequest.request({ - method: 'DELETE', - url: '/api/v1/groups/{group_id}/accounts/{account_id}', + method: "DELETE", + url: "/api/v1/groups/{group_id}/accounts/{account_id}", path: { - 'group_id': groupId, - 'account_id': accountId, + group_id: groupId, + account_id: accountId, }, errors: { 401: `unauthorized`, diff --git a/frontend/libs/api/src/lib/generated/services/AuthService.ts b/frontend/libs/api/src/lib/generated/services/AuthService.ts index d431750..58fc233 100644 --- a/frontend/libs/api/src/lib/generated/services/AuthService.ts +++ b/frontend/libs/api/src/lib/generated/services/AuthService.ts @@ -2,22 +2,22 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { Body_get_token } from '../models/Body_get_token'; -import type { ChangeEmailPayload } from '../models/ChangeEmailPayload'; -import type { ChangePasswordPayload } from '../models/ChangePasswordPayload'; -import type { ConfirmEmailChangePayload } from '../models/ConfirmEmailChangePayload'; -import type { ConfirmPasswordRecoveryPayload } from '../models/ConfirmPasswordRecoveryPayload'; -import type { ConfirmRegistrationPayload } from '../models/ConfirmRegistrationPayload'; -import type { DeleteSessionPayload } from '../models/DeleteSessionPayload'; -import type { LoginPayload } from '../models/LoginPayload'; -import type { RecoverPasswordPayload } from '../models/RecoverPasswordPayload'; -import type { RegisterPayload } from '../models/RegisterPayload'; -import type { RegisterResponse } from '../models/RegisterResponse'; -import type { RenameSessionPayload } from '../models/RenameSessionPayload'; -import type { Token } from '../models/Token'; -import type { User } from '../models/User'; -import type { CancelablePromise } from '../core/CancelablePromise'; -import type { BaseHttpRequest } from '../core/BaseHttpRequest'; +import type { Body_get_token } from "../models/Body_get_token"; +import type { ChangeEmailPayload } from "../models/ChangeEmailPayload"; +import type { ChangePasswordPayload } from "../models/ChangePasswordPayload"; +import type { ConfirmEmailChangePayload } from "../models/ConfirmEmailChangePayload"; +import type { ConfirmPasswordRecoveryPayload } from "../models/ConfirmPasswordRecoveryPayload"; +import type { ConfirmRegistrationPayload } from "../models/ConfirmRegistrationPayload"; +import type { DeleteSessionPayload } from "../models/DeleteSessionPayload"; +import type { LoginPayload } from "../models/LoginPayload"; +import type { RecoverPasswordPayload } from "../models/RecoverPasswordPayload"; +import type { RegisterPayload } from "../models/RegisterPayload"; +import type { RegisterResponse } from "../models/RegisterResponse"; +import type { RenameSessionPayload } from "../models/RenameSessionPayload"; +import type { Token } from "../models/Token"; +import type { User } from "../models/User"; +import type { CancelablePromise } from "../core/CancelablePromise"; +import type { BaseHttpRequest } from "../core/BaseHttpRequest"; export class AuthService { constructor(public readonly httpRequest: BaseHttpRequest) {} /** @@ -25,16 +25,12 @@ export class AuthService { * @returns Token Successful Response * @throws ApiError */ - public getToken({ - formData, - }: { - formData: Body_get_token, - }): CancelablePromise { + public getToken({ formData }: { formData: Body_get_token }): CancelablePromise { return this.httpRequest.request({ - method: 'POST', - url: '/api/v1/auth/token', + method: "POST", + url: "/api/v1/auth/token", formData: formData, - mediaType: 'application/x-www-form-urlencoded', + mediaType: "application/x-www-form-urlencoded", errors: { 422: `Validation Error`, }, @@ -45,16 +41,12 @@ export class AuthService { * @returns Token Successful Response * @throws ApiError */ - public login({ - requestBody, - }: { - requestBody: LoginPayload, - }): CancelablePromise { + public login({ requestBody }: { requestBody: LoginPayload }): CancelablePromise { return this.httpRequest.request({ - method: 'POST', - url: '/api/v1/auth/login', + method: "POST", + url: "/api/v1/auth/login", body: requestBody, - mediaType: 'application/json', + mediaType: "application/json", errors: { 422: `Validation Error`, }, @@ -67,8 +59,8 @@ export class AuthService { */ public logout(): CancelablePromise { return this.httpRequest.request({ - method: 'POST', - url: '/api/v1/auth/logout', + method: "POST", + url: "/api/v1/auth/logout", }); } /** @@ -76,16 +68,12 @@ export class AuthService { * @returns RegisterResponse Successful Response * @throws ApiError */ - public register({ - requestBody, - }: { - requestBody: RegisterPayload, - }): CancelablePromise { + public register({ requestBody }: { requestBody: RegisterPayload }): CancelablePromise { return this.httpRequest.request({ - method: 'POST', - url: '/api/v1/auth/register', + method: "POST", + url: "/api/v1/auth/register", body: requestBody, - mediaType: 'application/json', + mediaType: "application/json", errors: { 422: `Validation Error`, }, @@ -96,16 +84,12 @@ export class AuthService { * @returns void * @throws ApiError */ - public confirmRegistration({ - requestBody, - }: { - requestBody: ConfirmRegistrationPayload, - }): CancelablePromise { + public confirmRegistration({ requestBody }: { requestBody: ConfirmRegistrationPayload }): CancelablePromise { return this.httpRequest.request({ - method: 'POST', - url: '/api/v1/auth/confirm_registration', + method: "POST", + url: "/api/v1/auth/confirm_registration", body: requestBody, - mediaType: 'application/json', + mediaType: "application/json", errors: { 422: `Validation Error`, }, @@ -118,8 +102,8 @@ export class AuthService { */ public getProfile(): CancelablePromise { return this.httpRequest.request({ - method: 'GET', - url: '/api/v1/profile', + method: "GET", + url: "/api/v1/profile", }); } /** @@ -127,16 +111,12 @@ export class AuthService { * @returns void * @throws ApiError */ - public changePassword({ - requestBody, - }: { - requestBody: ChangePasswordPayload, - }): CancelablePromise { + public changePassword({ requestBody }: { requestBody: ChangePasswordPayload }): CancelablePromise { return this.httpRequest.request({ - method: 'POST', - url: '/api/v1/profile/change_password', + method: "POST", + url: "/api/v1/profile/change_password", body: requestBody, - mediaType: 'application/json', + mediaType: "application/json", errors: { 422: `Validation Error`, }, @@ -147,16 +127,12 @@ export class AuthService { * @returns void * @throws ApiError */ - public changeEmail({ - requestBody, - }: { - requestBody: ChangeEmailPayload, - }): CancelablePromise { + public changeEmail({ requestBody }: { requestBody: ChangeEmailPayload }): CancelablePromise { return this.httpRequest.request({ - method: 'POST', - url: '/api/v1/profile/change_email', + method: "POST", + url: "/api/v1/profile/change_email", body: requestBody, - mediaType: 'application/json', + mediaType: "application/json", errors: { 422: `Validation Error`, }, @@ -167,16 +143,12 @@ export class AuthService { * @returns void * @throws ApiError */ - public confirmEmailChange({ - requestBody, - }: { - requestBody: ConfirmEmailChangePayload, - }): CancelablePromise { + public confirmEmailChange({ requestBody }: { requestBody: ConfirmEmailChangePayload }): CancelablePromise { return this.httpRequest.request({ - method: 'POST', - url: '/api/v1/auth/confirm_email_change', + method: "POST", + url: "/api/v1/auth/confirm_email_change", body: requestBody, - mediaType: 'application/json', + mediaType: "application/json", errors: { 422: `Validation Error`, }, @@ -187,16 +159,12 @@ export class AuthService { * @returns void * @throws ApiError */ - public recoverPassword({ - requestBody, - }: { - requestBody: RecoverPasswordPayload, - }): CancelablePromise { + public recoverPassword({ requestBody }: { requestBody: RecoverPasswordPayload }): CancelablePromise { return this.httpRequest.request({ - method: 'POST', - url: '/api/v1/auth/recover_password', + method: "POST", + url: "/api/v1/auth/recover_password", body: requestBody, - mediaType: 'application/json', + mediaType: "application/json", errors: { 422: `Validation Error`, }, @@ -210,13 +178,13 @@ export class AuthService { public confirmPasswordRecovery({ requestBody, }: { - requestBody: ConfirmPasswordRecoveryPayload, + requestBody: ConfirmPasswordRecoveryPayload; }): CancelablePromise { return this.httpRequest.request({ - method: 'POST', - url: '/api/v1/auth/confirm_password_recovery', + method: "POST", + url: "/api/v1/auth/confirm_password_recovery", body: requestBody, - mediaType: 'application/json', + mediaType: "application/json", errors: { 422: `Validation Error`, }, @@ -227,16 +195,12 @@ export class AuthService { * @returns void * @throws ApiError */ - public deleteSession({ - requestBody, - }: { - requestBody: DeleteSessionPayload, - }): CancelablePromise { + public deleteSession({ requestBody }: { requestBody: DeleteSessionPayload }): CancelablePromise { return this.httpRequest.request({ - method: 'POST', - url: '/api/v1/auth/delete_session', + method: "POST", + url: "/api/v1/auth/delete_session", body: requestBody, - mediaType: 'application/json', + mediaType: "application/json", errors: { 422: `Validation Error`, }, @@ -247,16 +211,12 @@ export class AuthService { * @returns void * @throws ApiError */ - public renameSession({ - requestBody, - }: { - requestBody: RenameSessionPayload, - }): CancelablePromise { + public renameSession({ requestBody }: { requestBody: RenameSessionPayload }): CancelablePromise { return this.httpRequest.request({ - method: 'POST', - url: '/api/v1/auth/rename_session', + method: "POST", + url: "/api/v1/auth/rename_session", body: requestBody, - mediaType: 'application/json', + mediaType: "application/json", errors: { 422: `Validation Error`, }, diff --git a/frontend/libs/api/src/lib/generated/services/CommonService.ts b/frontend/libs/api/src/lib/generated/services/CommonService.ts index 4f6588f..9021c69 100644 --- a/frontend/libs/api/src/lib/generated/services/CommonService.ts +++ b/frontend/libs/api/src/lib/generated/services/CommonService.ts @@ -2,9 +2,9 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { VersionResponse } from '../models/VersionResponse'; -import type { CancelablePromise } from '../core/CancelablePromise'; -import type { BaseHttpRequest } from '../core/BaseHttpRequest'; +import type { VersionResponse } from "../models/VersionResponse"; +import type { CancelablePromise } from "../core/CancelablePromise"; +import type { BaseHttpRequest } from "../core/BaseHttpRequest"; export class CommonService { constructor(public readonly httpRequest: BaseHttpRequest) {} /** @@ -14,8 +14,8 @@ export class CommonService { */ public getVersion(): CancelablePromise { return this.httpRequest.request({ - method: 'GET', - url: '/api/version', + method: "GET", + url: "/api/version", }); } } diff --git a/frontend/libs/api/src/lib/generated/services/GroupsService.ts b/frontend/libs/api/src/lib/generated/services/GroupsService.ts index ddf3e5c..376afd5 100644 --- a/frontend/libs/api/src/lib/generated/services/GroupsService.ts +++ b/frontend/libs/api/src/lib/generated/services/GroupsService.ts @@ -2,18 +2,18 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { CreateInvitePayload } from '../models/CreateInvitePayload'; -import type { Group } from '../models/Group'; -import type { GroupInvite } from '../models/GroupInvite'; -import type { GroupLog } from '../models/GroupLog'; -import type { GroupMember } from '../models/GroupMember'; -import type { GroupMessage } from '../models/GroupMessage'; -import type { GroupPayload } from '../models/GroupPayload'; -import type { GroupPreview } from '../models/GroupPreview'; -import type { PreviewGroupPayload } from '../models/PreviewGroupPayload'; -import type { UpdateGroupMemberPayload } from '../models/UpdateGroupMemberPayload'; -import type { CancelablePromise } from '../core/CancelablePromise'; -import type { BaseHttpRequest } from '../core/BaseHttpRequest'; +import type { CreateInvitePayload } from "../models/CreateInvitePayload"; +import type { Group } from "../models/Group"; +import type { GroupInvite } from "../models/GroupInvite"; +import type { GroupLog } from "../models/GroupLog"; +import type { GroupMember } from "../models/GroupMember"; +import type { GroupMessage } from "../models/GroupMessage"; +import type { GroupPayload } from "../models/GroupPayload"; +import type { GroupPreview } from "../models/GroupPreview"; +import type { PreviewGroupPayload } from "../models/PreviewGroupPayload"; +import type { UpdateGroupMemberPayload } from "../models/UpdateGroupMemberPayload"; +import type { CancelablePromise } from "../core/CancelablePromise"; +import type { BaseHttpRequest } from "../core/BaseHttpRequest"; export class GroupsService { constructor(public readonly httpRequest: BaseHttpRequest) {} /** @@ -21,16 +21,12 @@ export class GroupsService { * @returns GroupPreview Successful Response * @throws ApiError */ - public previewGroup({ - requestBody, - }: { - requestBody: PreviewGroupPayload, - }): CancelablePromise { + public previewGroup({ requestBody }: { requestBody: PreviewGroupPayload }): CancelablePromise { return this.httpRequest.request({ - method: 'POST', - url: '/api/v1/groups/preview', + method: "POST", + url: "/api/v1/groups/preview", body: requestBody, - mediaType: 'application/json', + mediaType: "application/json", errors: { 401: `unauthorized`, 403: `forbidden`, @@ -44,16 +40,12 @@ export class GroupsService { * @returns Group Successful Response * @throws ApiError */ - public joinGroup({ - requestBody, - }: { - requestBody: PreviewGroupPayload, - }): CancelablePromise { + public joinGroup({ requestBody }: { requestBody: PreviewGroupPayload }): CancelablePromise { return this.httpRequest.request({ - method: 'POST', - url: '/api/v1/groups/join', + method: "POST", + url: "/api/v1/groups/join", body: requestBody, - mediaType: 'application/json', + mediaType: "application/json", errors: { 401: `unauthorized`, 403: `forbidden`, @@ -69,8 +61,8 @@ export class GroupsService { */ public listGroups(): CancelablePromise> { return this.httpRequest.request({ - method: 'GET', - url: '/api/v1/groups', + method: "GET", + url: "/api/v1/groups", errors: { 401: `unauthorized`, 403: `forbidden`, @@ -83,16 +75,12 @@ export class GroupsService { * @returns Group Successful Response * @throws ApiError */ - public createGroup({ - requestBody, - }: { - requestBody: GroupPayload, - }): CancelablePromise { + public createGroup({ requestBody }: { requestBody: GroupPayload }): CancelablePromise { return this.httpRequest.request({ - method: 'POST', - url: '/api/v1/groups', + method: "POST", + url: "/api/v1/groups", body: requestBody, - mediaType: 'application/json', + mediaType: "application/json", errors: { 401: `unauthorized`, 403: `forbidden`, @@ -106,16 +94,12 @@ export class GroupsService { * @returns Group Successful Response * @throws ApiError */ - public getGroup({ - groupId, - }: { - groupId: number, - }): CancelablePromise { + public getGroup({ groupId }: { groupId: number }): CancelablePromise { return this.httpRequest.request({ - method: 'GET', - url: '/api/v1/groups/{group_id}', + method: "GET", + url: "/api/v1/groups/{group_id}", path: { - 'group_id': groupId, + group_id: groupId, }, errors: { 401: `unauthorized`, @@ -134,17 +118,17 @@ export class GroupsService { groupId, requestBody, }: { - groupId: number, - requestBody: GroupPayload, + groupId: number; + requestBody: GroupPayload; }): CancelablePromise { return this.httpRequest.request({ - method: 'POST', - url: '/api/v1/groups/{group_id}', + method: "POST", + url: "/api/v1/groups/{group_id}", path: { - 'group_id': groupId, + group_id: groupId, }, body: requestBody, - mediaType: 'application/json', + mediaType: "application/json", errors: { 401: `unauthorized`, 403: `forbidden`, @@ -158,16 +142,12 @@ export class GroupsService { * @returns void * @throws ApiError */ - public deleteGroup({ - groupId, - }: { - groupId: number, - }): CancelablePromise { + public deleteGroup({ groupId }: { groupId: number }): CancelablePromise { return this.httpRequest.request({ - method: 'DELETE', - url: '/api/v1/groups/{group_id}', + method: "DELETE", + url: "/api/v1/groups/{group_id}", path: { - 'group_id': groupId, + group_id: groupId, }, errors: { 401: `unauthorized`, @@ -182,16 +162,12 @@ export class GroupsService { * @returns void * @throws ApiError */ - public leaveGroup({ - groupId, - }: { - groupId: number, - }): CancelablePromise { + public leaveGroup({ groupId }: { groupId: number }): CancelablePromise { return this.httpRequest.request({ - method: 'POST', - url: '/api/v1/groups/{group_id}/leave', + method: "POST", + url: "/api/v1/groups/{group_id}/leave", path: { - 'group_id': groupId, + group_id: groupId, }, errors: { 401: `unauthorized`, @@ -206,16 +182,12 @@ export class GroupsService { * @returns GroupMember Successful Response * @throws ApiError */ - public listMembers({ - groupId, - }: { - groupId: number, - }): CancelablePromise> { + public listMembers({ groupId }: { groupId: number }): CancelablePromise> { return this.httpRequest.request({ - method: 'GET', - url: '/api/v1/groups/{group_id}/members', + method: "GET", + url: "/api/v1/groups/{group_id}/members", path: { - 'group_id': groupId, + group_id: groupId, }, errors: { 401: `unauthorized`, @@ -234,17 +206,17 @@ export class GroupsService { groupId, requestBody, }: { - groupId: number, - requestBody: UpdateGroupMemberPayload, + groupId: number; + requestBody: UpdateGroupMemberPayload; }): CancelablePromise { return this.httpRequest.request({ - method: 'POST', - url: '/api/v1/groups/{group_id}/members', + method: "POST", + url: "/api/v1/groups/{group_id}/members", path: { - 'group_id': groupId, + group_id: groupId, }, body: requestBody, - mediaType: 'application/json', + mediaType: "application/json", errors: { 401: `unauthorized`, 403: `forbidden`, @@ -258,16 +230,12 @@ export class GroupsService { * @returns GroupLog Successful Response * @throws ApiError */ - public listLog({ - groupId, - }: { - groupId: number, - }): CancelablePromise> { + public listLog({ groupId }: { groupId: number }): CancelablePromise> { return this.httpRequest.request({ - method: 'GET', - url: '/api/v1/groups/{group_id}/logs', + method: "GET", + url: "/api/v1/groups/{group_id}/logs", path: { - 'group_id': groupId, + group_id: groupId, }, errors: { 401: `unauthorized`, @@ -286,17 +254,17 @@ export class GroupsService { groupId, requestBody, }: { - groupId: number, - requestBody: GroupMessage, + groupId: number; + requestBody: GroupMessage; }): CancelablePromise { return this.httpRequest.request({ - method: 'POST', - url: '/api/v1/groups/{group_id}/send_message', + method: "POST", + url: "/api/v1/groups/{group_id}/send_message", path: { - 'group_id': groupId, + group_id: groupId, }, body: requestBody, - mediaType: 'application/json', + mediaType: "application/json", errors: { 401: `unauthorized`, 403: `forbidden`, @@ -310,16 +278,12 @@ export class GroupsService { * @returns GroupInvite Successful Response * @throws ApiError */ - public listInvites({ - groupId, - }: { - groupId: number, - }): CancelablePromise> { + public listInvites({ groupId }: { groupId: number }): CancelablePromise> { return this.httpRequest.request({ - method: 'GET', - url: '/api/v1/groups/{group_id}/invites', + method: "GET", + url: "/api/v1/groups/{group_id}/invites", path: { - 'group_id': groupId, + group_id: groupId, }, errors: { 401: `unauthorized`, @@ -338,17 +302,17 @@ export class GroupsService { groupId, requestBody, }: { - groupId: number, - requestBody: CreateInvitePayload, + groupId: number; + requestBody: CreateInvitePayload; }): CancelablePromise { return this.httpRequest.request({ - method: 'POST', - url: '/api/v1/groups/{group_id}/invites', + method: "POST", + url: "/api/v1/groups/{group_id}/invites", path: { - 'group_id': groupId, + group_id: groupId, }, body: requestBody, - mediaType: 'application/json', + mediaType: "application/json", errors: { 401: `unauthorized`, 403: `forbidden`, @@ -362,19 +326,13 @@ export class GroupsService { * @returns void * @throws ApiError */ - public deleteInvite({ - groupId, - inviteId, - }: { - groupId: number, - inviteId: number, - }): CancelablePromise { + public deleteInvite({ groupId, inviteId }: { groupId: number; inviteId: number }): CancelablePromise { return this.httpRequest.request({ - method: 'DELETE', - url: '/api/v1/groups/{group_id}/invites/{invite_id}', + method: "DELETE", + url: "/api/v1/groups/{group_id}/invites/{invite_id}", path: { - 'group_id': groupId, - 'invite_id': inviteId, + group_id: groupId, + invite_id: inviteId, }, errors: { 401: `unauthorized`, @@ -389,16 +347,12 @@ export class GroupsService { * @returns any Successful Response * @throws ApiError */ - public archiveGroup({ - groupId, - }: { - groupId: number, - }): CancelablePromise { + public archiveGroup({ groupId }: { groupId: number }): CancelablePromise { return this.httpRequest.request({ - method: 'POST', - url: '/api/v1/groups/{group_id}/archive', + method: "POST", + url: "/api/v1/groups/{group_id}/archive", path: { - 'group_id': groupId, + group_id: groupId, }, errors: { 401: `unauthorized`, @@ -413,16 +367,12 @@ export class GroupsService { * @returns any Successful Response * @throws ApiError */ - public unarchiveGroup({ - groupId, - }: { - groupId: number, - }): CancelablePromise { + public unarchiveGroup({ groupId }: { groupId: number }): CancelablePromise { return this.httpRequest.request({ - method: 'POST', - url: '/api/v1/groups/{group_id}/un-archive', + method: "POST", + url: "/api/v1/groups/{group_id}/un-archive", path: { - 'group_id': groupId, + group_id: groupId, }, errors: { 401: `unauthorized`, diff --git a/frontend/libs/api/src/lib/generated/services/TransactionsService.ts b/frontend/libs/api/src/lib/generated/services/TransactionsService.ts index 2edb79f..49855b4 100644 --- a/frontend/libs/api/src/lib/generated/services/TransactionsService.ts +++ b/frontend/libs/api/src/lib/generated/services/TransactionsService.ts @@ -2,12 +2,12 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { NewTransaction } from '../models/NewTransaction'; -import type { Transaction } from '../models/Transaction'; -import type { UpdatePositionsPayload } from '../models/UpdatePositionsPayload'; -import type { UpdateTransaction } from '../models/UpdateTransaction'; -import type { CancelablePromise } from '../core/CancelablePromise'; -import type { BaseHttpRequest } from '../core/BaseHttpRequest'; +import type { NewTransaction } from "../models/NewTransaction"; +import type { Transaction } from "../models/Transaction"; +import type { UpdatePositionsPayload } from "../models/UpdatePositionsPayload"; +import type { UpdateTransaction } from "../models/UpdateTransaction"; +import type { CancelablePromise } from "../core/CancelablePromise"; +import type { BaseHttpRequest } from "../core/BaseHttpRequest"; export class TransactionsService { constructor(public readonly httpRequest: BaseHttpRequest) {} /** @@ -20,19 +20,19 @@ export class TransactionsService { minLastChanged, transactionIds, }: { - groupId: number, - minLastChanged?: (string | null), - transactionIds?: (string | null), + groupId: number; + minLastChanged?: string | null; + transactionIds?: string | null; }): CancelablePromise> { return this.httpRequest.request({ - method: 'GET', - url: '/api/v1/groups/{group_id}/transactions', + method: "GET", + url: "/api/v1/groups/{group_id}/transactions", path: { - 'group_id': groupId, + group_id: groupId, }, query: { - 'min_last_changed': minLastChanged, - 'transaction_ids': transactionIds, + min_last_changed: minLastChanged, + transaction_ids: transactionIds, }, errors: { 401: `unauthorized`, @@ -51,17 +51,17 @@ export class TransactionsService { groupId, requestBody, }: { - groupId: number, - requestBody: NewTransaction, + groupId: number; + requestBody: NewTransaction; }): CancelablePromise { return this.httpRequest.request({ - method: 'POST', - url: '/api/v1/groups/{group_id}/transactions', + method: "POST", + url: "/api/v1/groups/{group_id}/transactions", path: { - 'group_id': groupId, + group_id: groupId, }, body: requestBody, - mediaType: 'application/json', + mediaType: "application/json", errors: { 401: `unauthorized`, 403: `forbidden`, @@ -79,15 +79,15 @@ export class TransactionsService { groupId, transactionId, }: { - groupId: number, - transactionId: number, + groupId: number; + transactionId: number; }): CancelablePromise { return this.httpRequest.request({ - method: 'GET', - url: '/api/v1/groups/{group_id}/transactions/{transaction_id}', + method: "GET", + url: "/api/v1/groups/{group_id}/transactions/{transaction_id}", path: { - 'group_id': groupId, - 'transaction_id': transactionId, + group_id: groupId, + transaction_id: transactionId, }, errors: { 401: `unauthorized`, @@ -107,19 +107,19 @@ export class TransactionsService { transactionId, requestBody, }: { - groupId: number, - transactionId: number, - requestBody: UpdateTransaction, + groupId: number; + transactionId: number; + requestBody: UpdateTransaction; }): CancelablePromise { return this.httpRequest.request({ - method: 'POST', - url: '/api/v1/groups/{group_id}/transactions/{transaction_id}', + method: "POST", + url: "/api/v1/groups/{group_id}/transactions/{transaction_id}", path: { - 'group_id': groupId, - 'transaction_id': transactionId, + group_id: groupId, + transaction_id: transactionId, }, body: requestBody, - mediaType: 'application/json', + mediaType: "application/json", errors: { 401: `unauthorized`, 403: `forbidden`, @@ -137,15 +137,15 @@ export class TransactionsService { groupId, transactionId, }: { - groupId: number, - transactionId: number, + groupId: number; + transactionId: number; }): CancelablePromise { return this.httpRequest.request({ - method: 'DELETE', - url: '/api/v1/groups/{group_id}/transactions/{transaction_id}', + method: "DELETE", + url: "/api/v1/groups/{group_id}/transactions/{transaction_id}", path: { - 'group_id': groupId, - 'transaction_id': transactionId, + group_id: groupId, + transaction_id: transactionId, }, errors: { 401: `unauthorized`, @@ -165,19 +165,19 @@ export class TransactionsService { transactionId, requestBody, }: { - groupId: number, - transactionId: number, - requestBody: UpdatePositionsPayload, + groupId: number; + transactionId: number; + requestBody: UpdatePositionsPayload; }): CancelablePromise { return this.httpRequest.request({ - method: 'POST', - url: '/api/v1/groups/{group_id}/transactions/{transaction_id}/positions', + method: "POST", + url: "/api/v1/groups/{group_id}/transactions/{transaction_id}/positions", path: { - 'group_id': groupId, - 'transaction_id': transactionId, + group_id: groupId, + transaction_id: transactionId, }, body: requestBody, - mediaType: 'application/json', + mediaType: "application/json", errors: { 401: `unauthorized`, 403: `forbidden`, @@ -191,19 +191,13 @@ export class TransactionsService { * @returns any Successful Response * @throws ApiError */ - public getFileContents({ - fileId, - blobId, - }: { - fileId: number, - blobId: number, - }): CancelablePromise { + public getFileContents({ fileId, blobId }: { fileId: number; blobId: number }): CancelablePromise { return this.httpRequest.request({ - method: 'GET', - url: '/api/v1/files/{file_id}/{blob_id}', + method: "GET", + url: "/api/v1/files/{file_id}/{blob_id}", path: { - 'file_id': fileId, - 'blob_id': blobId, + file_id: fileId, + blob_id: blobId, }, errors: { 401: `unauthorized`, From cc209c459a9897d0fe5c4d26db82636311204e9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Loipf=C3=BChrer?= Date: Sun, 8 Sep 2024 18:32:14 +0200 Subject: [PATCH 9/9] fix(core): properly pass group_id kwargs in tests --- abrechnung/http/routers/accounts.py | 14 ++++++-------- abrechnung/http/routers/transactions.py | 10 +++++----- frontend/libs/api/project.json | 3 ++- tests/http_tests/test_groups.py | 18 +++++++++--------- tests/test_transaction_logic.py | 12 +++++++++--- tests/test_transactions.py | 14 ++++++++++---- 6 files changed, 41 insertions(+), 30 deletions(-) diff --git a/abrechnung/http/routers/accounts.py b/abrechnung/http/routers/accounts.py index 5d19890..43d7dd6 100644 --- a/abrechnung/http/routers/accounts.py +++ b/abrechnung/http/routers/accounts.py @@ -1,11 +1,9 @@ -from datetime import date -from typing import List, Optional +from typing import List from fastapi import APIRouter, Depends, status -from pydantic import BaseModel from abrechnung.application.accounts import AccountService -from abrechnung.domain.accounts import Account, ClearingShares, NewAccount +from abrechnung.domain.accounts import Account, NewAccount from abrechnung.domain.users import User from abrechnung.http.auth import get_current_user from abrechnung.http.dependencies import get_account_service @@ -53,7 +51,7 @@ async def create_account( account=payload, ) - return await account_service.get_account(user=user, account_id=account_id) + return await account_service.get_account(user=user, group_id=group_id, account_id=account_id) @router.get( @@ -68,7 +66,7 @@ async def get_account( user: User = Depends(get_current_user), account_service: AccountService = Depends(get_account_service), ): - return await account_service.get_account(user=user, account_id=account_id) + return await account_service.get_account(user=user, group_id=group_id, account_id=account_id) @router.post( @@ -91,7 +89,7 @@ async def update_account( account=payload, ) - return await account_service.get_account(user=user, account_id=account_id) + return await account_service.get_account(user=user, group_id=group_id, account_id=account_id) @router.delete( @@ -111,4 +109,4 @@ async def delete_account( user=user, account_id=account_id, ) - return await account_service.get_account(user=user, account_id=account_id) + return await account_service.get_account(user=user, group_id=group_id, account_id=account_id) diff --git a/abrechnung/http/routers/transactions.py b/abrechnung/http/routers/transactions.py index 9baf369..d011090 100644 --- a/abrechnung/http/routers/transactions.py +++ b/abrechnung/http/routers/transactions.py @@ -75,7 +75,7 @@ async def create_transaction( transaction=payload, ) - return await transaction_service.get_transaction(user=user, transaction_id=transaction_id) + return await transaction_service.get_transaction(user=user, group_id=group_id, transaction_id=transaction_id) @router.get( @@ -90,7 +90,7 @@ async def get_transaction( user: User = Depends(get_current_user), transaction_service: TransactionService = Depends(get_transaction_service), ): - return await transaction_service.get_transaction(user=user, transaction_id=transaction_id) + return await transaction_service.get_transaction(user=user, group_id=group_id, transaction_id=transaction_id) @router.post( @@ -109,7 +109,7 @@ async def update_transaction( await transaction_service.update_transaction( user=user, transaction_id=transaction_id, transaction=payload, group_id=group_id ) - return await transaction_service.get_transaction(user=user, transaction_id=transaction_id) + return await transaction_service.get_transaction(user=user, group_id=group_id, transaction_id=transaction_id) class UpdatePositionsPayload(BaseModel): @@ -135,7 +135,7 @@ async def update_transaction_positions( transaction_id=transaction_id, positions=payload.positions, ) - return await transaction_service.get_transaction(user=user, transaction_id=transaction_id) + return await transaction_service.get_transaction(user=user, group_id=group_id, transaction_id=transaction_id) @router.delete( @@ -155,7 +155,7 @@ async def delete_transaction( user=user, transaction_id=transaction_id, ) - return await transaction_service.get_transaction(user=user, transaction_id=transaction_id) + return await transaction_service.get_transaction(user=user, group_id=group_id, transaction_id=transaction_id) @router.get( diff --git a/frontend/libs/api/project.json b/frontend/libs/api/project.json index 8b5ddca..5ea3ef8 100644 --- a/frontend/libs/api/project.json +++ b/frontend/libs/api/project.json @@ -14,7 +14,8 @@ "sed -i 's/type: any/type: \"clearing\"/' src/lib/generated/models/ClearingAccount.ts", "echo \"/* eslint-disable */\\n$(cat src/lib/generated/schema.ts)\" > src/lib/generated/schema.ts", "echo \"/* tslint:disable */\\n$(cat src/lib/generated/schema.ts)\" > src/lib/generated/schema.ts", - "echo \"/* istanbul ignore file */\\n$(cat src/lib/generated/schema.ts)\" > src/lib/generated/schema.ts" + "echo \"/* istanbul ignore file */\\n$(cat src/lib/generated/schema.ts)\" > src/lib/generated/schema.ts", + "npx prettier --write src/lib/generated" ], "parallel": false, "cwd": "libs/api" diff --git a/tests/http_tests/test_groups.py b/tests/http_tests/test_groups.py index ef144a8..941e434 100644 --- a/tests/http_tests/test_groups.py +++ b/tests/http_tests/test_groups.py @@ -15,8 +15,8 @@ async def _fetch_group(self, group_id: int, expected_status: int = 200) -> dict: self.assertEqual(group_id, ret_data["id"]) return ret_data - async def _fetch_account(self, account_id: int, expected_status: int = 200) -> dict: - resp = await self._get(f"/api/v1/accounts/{account_id}") + async def _fetch_account(self, group_id: int, account_id: int, expected_status: int = 200) -> dict: + resp = await self._get(f"/api/v1/groups/{group_id}/accounts/{account_id}") self.assertEqual(expected_status, resp.status_code) if expected_status >= 400: return {} @@ -213,7 +213,7 @@ async def test_update_account(self): ), ) resp = await self._post( - f"/api/v1/accounts/{account_id}", + f"/api/v1/groups/{group_id}/accounts/{account_id}", json={ "type": "personal", "name": "new_name", @@ -222,12 +222,12 @@ async def test_update_account(self): ) self.assertEqual(200, resp.status_code) - a = await self._fetch_account(account_id) + a = await self._fetch_account(group_id, account_id) self.assertEqual("new_name", a["name"]) self.assertEqual("description", a["description"]) resp = await self._post( - f"/api/v1/accounts/{account_id}", + f"/api/v1/groups/{group_id}/accounts/{account_id}", json={ "type": "personal", "name": "new_name2", @@ -235,7 +235,7 @@ async def test_update_account(self): }, ) self.assertEqual(200, resp.status_code) - a = await self._fetch_account(account_id) + a = await self._fetch_account(group_id, account_id) self.assertEqual("new_name2", a["name"]) self.assertEqual("description1", a["description"]) @@ -338,13 +338,13 @@ async def test_get_account(self): description="description", ), ) - ret_data = await self._fetch_account(account_id) + ret_data = await self._fetch_account(group_id, account_id) self.assertEqual("account1", ret_data["name"]) - resp = await self._get(f"/api/v1/accounts/asdf1234") + resp = await self._get(f"/api/v1/groups/{group_id}/accounts/asdf1234") self.assertEqual(422, resp.status_code) - resp = await self._get(f"/api/v1/accounts/13232") + resp = await self._get(f"/api/v1/groups/{group_id}/accounts/13232") self.assertEqual(404, resp.status_code) async def test_invites(self): diff --git a/tests/test_transaction_logic.py b/tests/test_transaction_logic.py index a5d04a9..8f1ed3d 100644 --- a/tests/test_transaction_logic.py +++ b/tests/test_transaction_logic.py @@ -1,4 +1,4 @@ -# pylint: disable=attribute-defined-outside-init,missing-kwoa +# pylint: disable=attribute-defined-outside-init,missing-kwoa,unexpected-keyword-arg import base64 from datetime import datetime from pathlib import Path @@ -76,13 +76,16 @@ async def test_basic_clearing_account_workflow(self): ), ) - account: ClearingAccount = await self.account_service.get_account(user=self.user, account_id=account_id) + account: ClearingAccount = await self.account_service.get_account( + user=self.user, group_id=self.group_id, account_id=account_id + ) self.assertEqual(account_id, account.id) self.assertEqual(2.0, account.clearing_shares[basic_account_id2]) self.assertEqual(1.0, account.clearing_shares[basic_account_id1]) await self.account_service.update_account( user=self.user, + group_id=self.group_id, account_id=account_id, account=NewAccount( name="Clearing", @@ -92,7 +95,7 @@ async def test_basic_clearing_account_workflow(self): clearing_shares={basic_account_id1: 1.0}, ), ) - account = await self.account_service.get_account(user=self.user, account_id=account_id) + account = await self.account_service.get_account(user=self.user, group_id=self.group_id, account_id=account_id) self.assertTrue(basic_account_id2 not in account.clearing_shares) async def test_no_circular_clearing_accounts(self): @@ -121,6 +124,7 @@ async def test_no_circular_clearing_accounts(self): with self.assertRaises(Exception) as ctx: await self.account_service.update_account( user=self.user, + group_id=self.group_id, account_id=account1_id, account=NewAccount( name="account1", @@ -137,6 +141,7 @@ async def test_no_circular_clearing_accounts(self): with self.assertRaises(Exception) as ctx: await self.account_service.update_account( user=self.user, + group_id=self.group_id, account_id=account1_id, account=NewAccount( name="account1", @@ -186,6 +191,7 @@ async def test_file_upload(self): await self.transaction_service.update_transaction( user=self.user, + group_id=self.group_id, transaction_id=transaction_id, transaction=UpdateTransaction( type=TransactionType.purchase, diff --git a/tests/test_transactions.py b/tests/test_transactions.py index 733bf64..48c6955 100644 --- a/tests/test_transactions.py +++ b/tests/test_transactions.py @@ -1,4 +1,4 @@ -# pylint: disable=missing-kwoa +# pylint: disable=missing-kwoa,unexpected-keyword-arg from datetime import date, datetime @@ -159,6 +159,7 @@ async def test_update_transaction(self): ) await self.transaction_service.update_transaction( user=self.test_user, + group_id=group_id, transaction_id=transaction_id, transaction=UpdateTransaction( type=TransactionType.purchase, @@ -175,7 +176,8 @@ async def test_update_transaction(self): ) t: Transaction = await self.transaction_service.get_transaction( - user=self.test_user, transaction_id=transaction_id + user=self.test_user, + transaction_id=transaction_id, ) self.assertEqual(200.0, t.value) self.assertEqual( @@ -187,6 +189,7 @@ async def test_update_transaction(self): await self.transaction_service.update_transaction( user=self.test_user, + group_id=group_id, transaction_id=transaction_id, transaction=UpdateTransaction( type=TransactionType.purchase, @@ -257,12 +260,13 @@ async def test_account_deletion(self): ) # we can delete the account when nothing depends on it - await self.account_service.delete_account(user=self.test_user, account_id=account1_id) + await self.account_service.delete_account(user=self.test_user, group_id=group_id, account_id=account1_id) # the account has been deleted, we should not be able to add more shares to it with self.assertRaises(Exception): await self.transaction_service.update_transaction( user=self.test_user, + group_id=group_id, transaction_id=transaction_id, transaction=UpdateTransaction( type=TransactionType.purchase, @@ -283,6 +287,7 @@ async def test_account_deletion(self): await self.transaction_service.update_transaction( user=self.test_user, + group_id=group_id, transaction_id=transaction_id, transaction=UpdateTransaction( type=TransactionType.purchase, @@ -298,7 +303,7 @@ async def test_account_deletion(self): ), ) # we should not be able to delete this account as changes depend on it - await self.account_service.delete_account(user=self.test_user, account_id=account2_id) + await self.account_service.delete_account(user=self.test_user, group_id=group_id, account_id=account2_id) async def test_purchase_items(self): group_id = await self._create_group() @@ -350,6 +355,7 @@ async def test_purchase_items(self): position_id = t.positions[0].id await self.transaction_service.update_transaction( user=self.test_user, + group_id=group_id, transaction_id=transaction_id, transaction=UpdateTransaction( type=TransactionType.purchase,