From 23d5a8096663df892b4496ad0190b15456aedc53 Mon Sep 17 00:00:00 2001 From: swve Date: Thu, 15 Jun 2023 19:39:18 +0200 Subject: [PATCH 1/2] feat: migrate org settings to server components --- .../organization/general/organization.tsx | 101 ++++++++++++++ .../settings/organization/general/page.tsx | 132 ++++-------------- front/app/orgs/[orgslug]/settings/page.tsx | 21 ++- src/services/orgs.py | 19 +-- 4 files changed, 156 insertions(+), 117 deletions(-) create mode 100644 front/app/orgs/[orgslug]/settings/organization/general/organization.tsx diff --git a/front/app/orgs/[orgslug]/settings/organization/general/organization.tsx b/front/app/orgs/[orgslug]/settings/organization/general/organization.tsx new file mode 100644 index 00000000..df5cdb9a --- /dev/null +++ b/front/app/orgs/[orgslug]/settings/organization/general/organization.tsx @@ -0,0 +1,101 @@ +"use client"; +import React from 'react' +import { Field, Form, Formik } from 'formik'; +import { updateOrganization } from '@services/settings/org'; + + +interface OrganizationValues { + name: string; + description: string; + slug: string; + email: string; +} + + +function OrganizationClient(props: any) { + const org = props.org; + let orgValues: OrganizationValues = { + name: org.name, + description: org.description, + slug: org.slug, + email: org.email + } + + const updateOrg = async (values: OrganizationValues) => { + let org_id = org.org_id; + await updateOrganization(org_id, values); + } + + return ( +
+

Organization Settings

+

+ + + { + setTimeout(() => { + alert(JSON.stringify(values, null, 2)); + setSubmitting(false); + updateOrg(values) + }, 400); + }} + > + {({ isSubmitting }) => ( +
+ + + + + + + + + + + + + + + + )} +
+ + +
+ ) +} + +export default OrganizationClient \ No newline at end of file diff --git a/front/app/orgs/[orgslug]/settings/organization/general/page.tsx b/front/app/orgs/[orgslug]/settings/organization/general/page.tsx index 63c4b227..b5077f4b 100644 --- a/front/app/orgs/[orgslug]/settings/organization/general/page.tsx +++ b/front/app/orgs/[orgslug]/settings/organization/general/page.tsx @@ -1,115 +1,33 @@ -"use client"; -import React from 'react' -import useSWR, { mutate } from "swr"; -import { swrFetcher } from "@services/utils/ts/requests"; -import { getAPIUrl } from '@services/config/config'; -import { Field, Form, Formik } from 'formik'; -import { updateOrganization } from '@services/settings/org'; +import { getOrganizationContextInfo } from '@services/organizations/orgs'; +import { Metadata } from 'next'; +import OrganizationClient from './organization'; -interface OrganizationValues { - name: string; - description: string; - slug: string; - email: string; +type MetadataProps = { + params: { orgslug: string }; + searchParams: { [key: string]: string | string[] | undefined }; +}; + +export async function generateMetadata( + { params }: MetadataProps, +): Promise { + + // Get Org context information + const org = await getOrganizationContextInfo(params.orgslug, { revalidate: 1800, tags: ['organizations'] }); + return { + title: `Settings: General — ${org.name}`, + description: org.description, + }; } -function SettingsOrganizationGeneral(params: any) { +async function SettingsOrganizationGeneral(params: any) { const orgslug = params.params.orgslug; - const { data: org, error: error } = useSWR(`${getAPIUrl()}orgs/slug/${orgslug}`, swrFetcher); + const org = await getOrganizationContextInfo(orgslug, { revalidate: 1800, tags: ['organizations'] }); - if (org) { - let orgValues: OrganizationValues = { - name: org.name, - description: org.description, - slug: org.slug, - email: org.email - } - - - const updateOrg = async (values: OrganizationValues) => { - let org_id = org.org_id; - await updateOrganization(org_id, values); - - // Sounds good, doesn't work - // TODO: Fix this - mutate(`${getAPIUrl()}orgs/slug/${values.slug}`); - } - - return ( -
-

Oganization Settings

-

- {error &&

Failed to load

} - {!org ? ( -
Loading...
- ) : ( - - { - setTimeout(() => { - alert(JSON.stringify(values, null, 2)); - setSubmitting(false); - updateOrg(values) - }, 400); - }} - > - {({ isSubmitting }) => ( -
- - - - - - - - - - - - - - - - )} -
- )} - - -
- ) - } + return ( + <> + + + ) } export default SettingsOrganizationGeneral \ No newline at end of file diff --git a/front/app/orgs/[orgslug]/settings/page.tsx b/front/app/orgs/[orgslug]/settings/page.tsx index 77919d58..8fd3f1d7 100644 --- a/front/app/orgs/[orgslug]/settings/page.tsx +++ b/front/app/orgs/[orgslug]/settings/page.tsx @@ -1,4 +1,23 @@ -import React from 'react' +import { getOrganizationContextInfo } from "@services/organizations/orgs"; +import { Metadata, ResolvingMetadata } from 'next'; + +type MetadataProps = { + params: { orgslug: string }; + searchParams: { [key: string]: string | string[] | undefined }; +}; + +export async function generateMetadata( + { params }: MetadataProps, +): Promise { + + + // Get Org context information + const org = await getOrganizationContextInfo(params.orgslug, { revalidate: 1800, tags: ['organizations'] }); + return { + title: `Settings — ${org.name}`, + description: org.description, + }; +} function Settings() { return ( diff --git a/src/services/orgs.py b/src/services/orgs.py index a213b2d0..ae570e75 100644 --- a/src/services/orgs.py +++ b/src/services/orgs.py @@ -1,5 +1,7 @@ import json +from typing import Optional from uuid import uuid4 +from click import Option from pydantic import BaseModel from src.services.users.schemas.users import UserOrganization from src.services.users.users import PublicUser @@ -14,7 +16,7 @@ class Organization(BaseModel): description: str email: str slug: str - default: bool + default: Optional[bool] class OrganizationInDB(Organization): @@ -106,11 +108,8 @@ async def update_org(request: Request, org_object: Organization, org_id: str, cu org = await orgs.find_one({"org_id": org_id}) - if org: - org["owners"] - org["admins"] + if not org: - else: raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail="Organization does not exist") @@ -185,12 +184,14 @@ async def verify_org_rights(request: Request, org_id: str, current_user: Public raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail="Organization does not exist") - isOwner = current_user.user_id in org["owners"] + # check if is owner of org + # todo check if is admin of org + hasRoleRights = await verify_user_rights_with_roles(request, action, current_user.user_id, org_id, org_id) - if not hasRoleRights and not isOwner: - raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, detail="You do not have rights to this organization") + # if not hasRoleRights and not isOwner: + # raise HTTPException( + # status_code=status.HTTP_403_FORBIDDEN, detail="You do not have rights to this organization") return True From 21171976b4c9ed9346297acb9e4284ffb1fe2c04 Mon Sep 17 00:00:00 2001 From: swve Date: Thu, 15 Jun 2023 19:49:54 +0200 Subject: [PATCH 2/2] feat: migrate rest of settings to serv comps --- .../settings/account/passwords/page.tsx | 97 +++++-------------- .../settings/account/passwords/passwords.tsx | 77 +++++++++++++++ .../settings/account/profile/page.tsx | 95 ++++-------------- .../settings/account/profile/profile.tsx | 79 +++++++++++++++ 4 files changed, 202 insertions(+), 146 deletions(-) create mode 100644 front/app/orgs/[orgslug]/settings/account/passwords/passwords.tsx create mode 100644 front/app/orgs/[orgslug]/settings/account/profile/profile.tsx diff --git a/front/app/orgs/[orgslug]/settings/account/passwords/page.tsx b/front/app/orgs/[orgslug]/settings/account/passwords/page.tsx index 4bca9638..af13c2b2 100644 --- a/front/app/orgs/[orgslug]/settings/account/passwords/page.tsx +++ b/front/app/orgs/[orgslug]/settings/account/passwords/page.tsx @@ -1,77 +1,30 @@ -"use client"; -import { AuthContext } from '@components/Security/AuthProvider'; -import React, { useEffect } from 'react' -import { Formik, Form, Field, ErrorMessage } from 'formik'; -import { updateProfile } from '@services/settings/profile'; -import { updatePassword } from '@services/settings/password'; +import { getOrganizationContextInfo } from "@services/organizations/orgs"; +import { Metadata } from "next"; +import PasswordsClient from "./passwords"; + +type MetadataProps = { + params: { orgslug: string }; + searchParams: { [key: string]: string | string[] | undefined }; +}; + +export async function generateMetadata( + { params }: MetadataProps, +): Promise { + + // Get Org context information + const org = await getOrganizationContextInfo(params.orgslug, { revalidate: 1800, tags: ['organizations'] }); + return { + title: `Settings: Passwords — ${org.name}`, + description: org.description, + }; +} function SettingsProfilePasswordsPage() { - - const auth: any = React.useContext(AuthContext); - - const updatePasswordUI = async (values: any) => { - let user_id = auth.userInfo.user_object.user_id; - console.log(values); - await updatePassword(user_id, values) - } - - - return ( -
- - {auth.isAuthenticated && ( -
-

Account Password

-

- - { - setTimeout(() => { - alert(JSON.stringify(values, null, 2)); - setSubmitting(false); - updatePasswordUI(values) - }, 400); - }} - > - {({ isSubmitting }) => ( -
- - - - - - - - - - )} -
-
- )} - - -
- - ) + return ( + <> + + + ) } export default SettingsProfilePasswordsPage \ No newline at end of file diff --git a/front/app/orgs/[orgslug]/settings/account/passwords/passwords.tsx b/front/app/orgs/[orgslug]/settings/account/passwords/passwords.tsx new file mode 100644 index 00000000..c2254a34 --- /dev/null +++ b/front/app/orgs/[orgslug]/settings/account/passwords/passwords.tsx @@ -0,0 +1,77 @@ +"use client"; +import { AuthContext } from '@components/Security/AuthProvider'; +import React, { useEffect } from 'react' +import { Formik, Form, Field, ErrorMessage } from 'formik'; +import { updatePassword } from '@services/settings/password'; + + +function PasswordsClient() { + const auth: any = React.useContext(AuthContext); + + console.log('auth', auth) + + const updatePasswordUI = async (values: any) => { + let user_id = auth.userInfo.user_object.user_id; + await updatePassword(user_id, values) + } + + + return ( +
+ + {auth.isAuthenticated && ( +
+

Account Password

+

+ + { + setTimeout(() => { + alert(JSON.stringify(values, null, 2)); + setSubmitting(false); + updatePasswordUI(values) + }, 400); + }} + > + {({ isSubmitting }) => ( +
+ + + + + + + + + + )} +
+
+ )} + + +
+ + ) +} + +export default PasswordsClient \ No newline at end of file diff --git a/front/app/orgs/[orgslug]/settings/account/profile/page.tsx b/front/app/orgs/[orgslug]/settings/account/profile/page.tsx index ea0e297b..31139edc 100644 --- a/front/app/orgs/[orgslug]/settings/account/profile/page.tsx +++ b/front/app/orgs/[orgslug]/settings/account/profile/page.tsx @@ -1,79 +1,26 @@ -"use client"; -import { AuthContext } from '@components/Security/AuthProvider'; -import React, { useEffect } from 'react' -import { Formik, Form, Field, ErrorMessage } from 'formik'; -import { updateProfile } from '@services/settings/profile'; +import { getOrganizationContextInfo } from "@services/organizations/orgs"; +import { Metadata } from "next"; +import ProfileClient from "./profile"; + +type MetadataProps = { + params: { orgslug: string }; + searchParams: { [key: string]: string | string[] | undefined }; +}; + +export async function generateMetadata( + { params }: MetadataProps, +): Promise { + + // Get Org context information + const org = await getOrganizationContextInfo(params.orgslug, { revalidate: 1800, tags: ['organizations'] }); + return { + title: `Settings: Profile — ${org.name}`, + description: org.description, + }; +} function SettingsProfilePage() { - const auth: any = React.useContext(AuthContext); - - return ( -
- - {auth.isAuthenticated && ( -
-

Profile Settings

-

- - { - setTimeout(() => { - alert(JSON.stringify(values, null, 2)); - setSubmitting(false); - updateProfile(values) - }, 400); - }} - > - {({ isSubmitting }) => ( -
- - - - - - - - - - - - - )} -
-
- )} - - -
- - ) + return } export default SettingsProfilePage \ No newline at end of file diff --git a/front/app/orgs/[orgslug]/settings/account/profile/profile.tsx b/front/app/orgs/[orgslug]/settings/account/profile/profile.tsx new file mode 100644 index 00000000..8423de4f --- /dev/null +++ b/front/app/orgs/[orgslug]/settings/account/profile/profile.tsx @@ -0,0 +1,79 @@ +"use client"; +import { AuthContext } from '@components/Security/AuthProvider'; +import React, { useEffect } from 'react' +import { Formik, Form, Field, ErrorMessage } from 'formik'; +import { updateProfile } from '@services/settings/profile'; + +function ProfileClient() { + const auth: any = React.useContext(AuthContext); + + return ( +
+ + {auth.isAuthenticated && ( +
+

Profile Settings

+

+ + { + setTimeout(() => { + alert(JSON.stringify(values, null, 2)); + setSubmitting(false); + updateProfile(values) + }, 400); + }} + > + {({ isSubmitting }) => ( +
+ + + + + + + + + + + + + )} +
+
+ )} + + +
+ + ) +} + +export default ProfileClient \ No newline at end of file