fix menu
This commit is contained in:
@@ -117,9 +117,10 @@ def _create_user(user: User, org: Org) -> bool:
|
||||
'sk': '0',
|
||||
'email_verified': email_verified,
|
||||
'tenant_id': {org.id},
|
||||
# Post-migration: uncomment the folloing line
|
||||
# Post-migration (users): uncomment the folloing line
|
||||
# 'org_id': {org.id},
|
||||
'created_at': now_,
|
||||
# 'created_at': now_,
|
||||
'createDate': now_,
|
||||
},
|
||||
)
|
||||
transact.put(
|
||||
@@ -157,9 +158,10 @@ def _create_user(user: User, org: Org) -> bool:
|
||||
|
||||
transact.put(
|
||||
item={
|
||||
# Post-migration: rename `cpf` to `CPF`
|
||||
# Post-migration (users): rename `cpf` to `CPF`
|
||||
'id': 'cpf',
|
||||
'sk': user.cpf,
|
||||
'user_id': user_id,
|
||||
'created_at': now_,
|
||||
},
|
||||
cond_expr='attribute_not_exists(sk)',
|
||||
@@ -167,9 +169,10 @@ def _create_user(user: User, org: Org) -> bool:
|
||||
)
|
||||
transact.put(
|
||||
item={
|
||||
# Post-migration: rename `email` to `EMAIL`
|
||||
# Post-migration (users): rename `email` to `EMAIL`
|
||||
'id': 'email',
|
||||
'sk': user.email,
|
||||
'user_id': user_id,
|
||||
'created_at': now_,
|
||||
},
|
||||
cond_expr='attribute_not_exists(sk)',
|
||||
@@ -179,7 +182,7 @@ def _create_user(user: User, org: Org) -> bool:
|
||||
item={
|
||||
'id': user_id,
|
||||
'sk': f'orgs#{org.id}',
|
||||
# Post-migration: uncomment the following line
|
||||
# Post-migration (users): uncomment the following line
|
||||
# pk=f'ORG#{org.id}',
|
||||
'name': org.name,
|
||||
'cnpj': org.cnpj,
|
||||
@@ -189,7 +192,7 @@ def _create_user(user: User, org: Org) -> bool:
|
||||
transact.put(
|
||||
item={
|
||||
'id': f'orgmembers#{org.id}',
|
||||
# Post-migration: uncomment the following line
|
||||
# Post-migration (users): uncomment the following line
|
||||
# pk=f'MEMBER#ORG#{org_id}',
|
||||
'sk': user_id,
|
||||
'created_at': now_,
|
||||
@@ -212,7 +215,7 @@ def _add_member(user_id: str, org: Org) -> None:
|
||||
with dyn.transact_writer() as transact:
|
||||
transact.update(
|
||||
key=KeyPair(user_id, '0'),
|
||||
# Post-migration: uncomment the following line
|
||||
# Post-migration (users): uncomment the following line
|
||||
# update_expr='ADD tenant_id :org_id',
|
||||
update_expr='ADD tenant_id :org_id',
|
||||
expr_attr_values={
|
||||
@@ -224,7 +227,7 @@ def _add_member(user_id: str, org: Org) -> None:
|
||||
transact.put(
|
||||
item={
|
||||
'id': user_id,
|
||||
# Post-migration: rename `orgs` to `ORG`
|
||||
# Post-migration (users): rename `orgs` to `ORG`
|
||||
'sk': f'orgs#{org.id}',
|
||||
'name': org.name,
|
||||
'cnpj': org.cnpj,
|
||||
@@ -233,7 +236,8 @@ def _add_member(user_id: str, org: Org) -> None:
|
||||
)
|
||||
transact.put(
|
||||
item={
|
||||
# Post-migration: rename `orgmembers` to `ORGMEMBER`
|
||||
# Post-migration (users): uncomment the following line
|
||||
# pk=f'MEMBER#ORG#{org_id}',
|
||||
'id': f'orgmembers#{org.id}',
|
||||
'sk': user_id,
|
||||
'created_at': now_,
|
||||
|
||||
@@ -59,7 +59,7 @@ def get_user(user_id: str):
|
||||
)
|
||||
|
||||
if not user:
|
||||
return UserNotFoundError('User not found')
|
||||
raise UserNotFoundError('User not found')
|
||||
|
||||
return user
|
||||
|
||||
@@ -74,10 +74,7 @@ def update(
|
||||
old_cpf = dyn.collection.get_item(
|
||||
KeyPair(
|
||||
pk=user_id,
|
||||
sk=SortKey(
|
||||
'0',
|
||||
path_spec='cpf',
|
||||
),
|
||||
sk=SortKey('0', path_spec='cpf'),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ export async function loader({ params, request, context }: Route.LoaderArgs) {
|
||||
})
|
||||
|
||||
if (!r.ok) {
|
||||
console.log(r.status)
|
||||
throw new Response(null, { status: r.status })
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ export default function Route({ loaderData }: Route.ComponentProps) {
|
||||
<div className="ml-auto flex gap-2.5 items-center">
|
||||
<Notification />
|
||||
<ModeToggle />
|
||||
<NavUser user={user} />
|
||||
<NavUser user={user} excludeApps={['admin']} />
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -56,9 +56,7 @@ export async function action({ request, context }: Route.ActionArgs) {
|
||||
try {
|
||||
const r = await fetch(issuerUrl.toString(), {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
headers: new Headers({ 'Content-Type': 'application/json' }),
|
||||
body: JSON.stringify(formData)
|
||||
})
|
||||
|
||||
@@ -88,10 +86,7 @@ export async function action({ request, context }: Route.ActionArgs) {
|
||||
export default function Index({}: Route.ComponentProps) {
|
||||
const [show, setShow] = useState(false)
|
||||
const fetcher = useFetcher()
|
||||
|
||||
const form = useForm({
|
||||
resolver: zodResolver(schema)
|
||||
})
|
||||
const form = useForm({ resolver: zodResolver(schema) })
|
||||
const { control, handleSubmit, formState, setError } = form
|
||||
|
||||
const onSubmit = async (data: Schema) => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { Route } from '../+types'
|
||||
|
||||
import { useRequest } from 'ahooks'
|
||||
import { PatternFormat } from 'react-number-format'
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { useState } from 'react'
|
||||
@@ -31,6 +32,19 @@ export function meta({}: Route.MetaArgs) {
|
||||
return [{ title: 'Criar conta · EDUSEG®' }]
|
||||
}
|
||||
|
||||
export async function action({ request, context }: Route.ActionArgs) {
|
||||
const issuerUrl = new URL('/register', context.cloudflare.env.ISSUER_URL)
|
||||
const body = await request.json()
|
||||
|
||||
const r = await fetch(issuerUrl.toString(), {
|
||||
method: 'POST',
|
||||
headers: new Headers({ 'Content-Type': 'application/json' }),
|
||||
body: JSON.stringify(body)
|
||||
})
|
||||
|
||||
console.log(await r.json())
|
||||
}
|
||||
|
||||
export default function Signup({}: Route.ComponentProps) {
|
||||
const [show, setShow] = useState(false)
|
||||
const [user, setUser] = useState<User | null>(null)
|
||||
@@ -38,13 +52,21 @@ export default function Signup({}: Route.ComponentProps) {
|
||||
resolver: zodResolver(formSchema)
|
||||
})
|
||||
const { control, handleSubmit, formState } = form
|
||||
const { runAsync } = useRequest(
|
||||
async (user) => {
|
||||
return await fetch(`/register`, {
|
||||
method: 'POST',
|
||||
headers: new Headers({ 'Content-Type': 'application/json' }),
|
||||
body: JSON.stringify(user)
|
||||
})
|
||||
},
|
||||
{ manual: true }
|
||||
)
|
||||
|
||||
const onSubmit = async (data: Schema) => {
|
||||
console.log(data)
|
||||
await runAsync({ ...user, ...data })
|
||||
}
|
||||
|
||||
console.log(user)
|
||||
|
||||
return (
|
||||
<RegisterContext value={{ user, setUser }}>
|
||||
{user ? (
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
],
|
||||
"compilerOptions": {
|
||||
"checkJs": true,
|
||||
"moduleResolution": "bundler",
|
||||
"verbatimModuleSyntax": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
|
||||
@@ -48,7 +48,7 @@ export default function Route({ loaderData }: Route.ComponentProps) {
|
||||
|
||||
<div className="ml-auto flex gap-2.5 items-center">
|
||||
<ModeToggle />
|
||||
<NavUser user={user} />
|
||||
<NavUser user={user} excludeApps={['insights']} />
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -176,10 +176,22 @@ function List({ s, hits = [] }: { s: string; hits: Enrollment[] }) {
|
||||
<EmptyMedia variant="icon">
|
||||
<BanIcon />
|
||||
</EmptyMedia>
|
||||
{s ? (
|
||||
<>
|
||||
<EmptyTitle>Nada encontrado</EmptyTitle>
|
||||
<EmptyDescription>
|
||||
Nenhum resultado para <mark>{s}</mark>.
|
||||
</EmptyDescription>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<EmptyTitle>Nenhum curso ainda</EmptyTitle>
|
||||
<EmptyDescription>
|
||||
Comece escolhendo um curso. Assim que você se matricular, ele
|
||||
aparecerá aqui.
|
||||
</EmptyDescription>
|
||||
</>
|
||||
)}
|
||||
</EmptyHeader>
|
||||
</Empty>
|
||||
)
|
||||
|
||||
@@ -141,7 +141,7 @@ export default function Component({
|
||||
|
||||
<div className="ml-auto flex gap-2.5 items-center">
|
||||
<ModeToggle />
|
||||
<NavUser user={user} />
|
||||
<NavUser user={user} excludeApps={['saladeaula']} />
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -32,7 +32,7 @@ export default function Component({ loaderData }: Route.ComponentProps) {
|
||||
|
||||
<div className="ml-auto flex gap-2.5 items-center">
|
||||
<ModeToggle />
|
||||
<NavUser user={user} />
|
||||
<NavUser user={user} excludeApps={['studio']} />
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -13,5 +13,11 @@ OAUTH2_SCOPES_SUPPORTED: list[str] = [
|
||||
'apps:studio',
|
||||
'apps:insights',
|
||||
]
|
||||
OAUTH2_DEFAULT_SCOPES = {
|
||||
'email',
|
||||
'offline_access',
|
||||
'openid',
|
||||
'profile',
|
||||
}
|
||||
|
||||
SESSION_EXPIRES_IN = 86_400 * 30 # 30 days
|
||||
|
||||
0
id.saladeaula.digital/app/events/__init__.py
Normal file
0
id.saladeaula.digital/app/events/__init__.py
Normal file
@@ -21,7 +21,7 @@ from layercake.dynamodb import (
|
||||
from layercake.funcs import omit, pick
|
||||
|
||||
from boto3clients import dynamodb_client
|
||||
from config import ISSUER, OAUTH2_SCOPES_SUPPORTED, OAUTH2_TABLE
|
||||
from config import ISSUER, OAUTH2_DEFAULT_SCOPES, OAUTH2_SCOPES_SUPPORTED, OAUTH2_TABLE
|
||||
from integrations.apigateway_oauth2.authorization_server import (
|
||||
AuthorizationServer,
|
||||
)
|
||||
@@ -191,10 +191,11 @@ class AuthorizationCodeGrant(grants.AuthorizationCodeGrant):
|
||||
rename_key='scope',
|
||||
),
|
||||
)
|
||||
scope = set(user.get('scope', [])) | OAUTH2_DEFAULT_SCOPES
|
||||
|
||||
return User(
|
||||
**pick(('id', 'name', 'email', 'email_verified'), user),
|
||||
scope=' '.join(user['scope']) if 'scope' in user else None,
|
||||
scope=' '.join(scope),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -5,13 +5,14 @@ from aws_lambda_powertools.event_handler.api_gateway import Router
|
||||
from aws_lambda_powertools.event_handler.exceptions import (
|
||||
BadRequestError,
|
||||
ForbiddenError,
|
||||
NotFoundError,
|
||||
ServiceError,
|
||||
)
|
||||
from joserfc.errors import JoseError
|
||||
from layercake.dynamodb import DynamoDBPersistenceLayer, KeyPair, SortKey
|
||||
|
||||
from boto3clients import dynamodb_client
|
||||
from config import OAUTH2_TABLE
|
||||
from config import OAUTH2_DEFAULT_SCOPES, OAUTH2_TABLE
|
||||
from oauth2 import server
|
||||
from util import parse_cookies
|
||||
|
||||
@@ -20,6 +21,9 @@ logger = Logger(__name__)
|
||||
dyn = DynamoDBPersistenceLayer(OAUTH2_TABLE, dynamodb_client)
|
||||
|
||||
|
||||
class SessionNotFoundError(NotFoundError): ...
|
||||
|
||||
|
||||
@router.get('/authorize')
|
||||
def authorize():
|
||||
current_event = router.current_event
|
||||
@@ -27,20 +31,20 @@ def authorize():
|
||||
session = cookies.get('SID')
|
||||
|
||||
if not session:
|
||||
raise BadRequestError('Missing session')
|
||||
raise BadRequestError('Session cookie (SID) is required')
|
||||
|
||||
try:
|
||||
sid, sub = session.split(':')
|
||||
session_id, user_id = session.split(':')
|
||||
# Raise if session is not found
|
||||
dyn.collection.get_item(
|
||||
KeyPair('SESSION', sid),
|
||||
exc_cls=InvalidSession,
|
||||
KeyPair('SESSION', session_id),
|
||||
exc_cls=SessionNotFoundError,
|
||||
)
|
||||
grant = server.get_consent_grant(
|
||||
request=router.current_event,
|
||||
end_user=sub,
|
||||
end_user=user_id,
|
||||
)
|
||||
user_scopes = _user_scopes(sub)
|
||||
user_scopes = _user_scopes(user_id)
|
||||
client_scopes = set(scope_to_list(grant.client.scope))
|
||||
|
||||
# Deny authorization if user lacks scopes requested by client
|
||||
@@ -49,7 +53,7 @@ def authorize():
|
||||
|
||||
response = server.create_authorization_response(
|
||||
request=router.current_event,
|
||||
grant_user=sub,
|
||||
grant_user=user_id,
|
||||
grant=grant,
|
||||
)
|
||||
except JoseError as err:
|
||||
@@ -65,18 +69,16 @@ def authorize():
|
||||
return response
|
||||
|
||||
|
||||
def _user_scopes(sub: str) -> set:
|
||||
return set(
|
||||
def _user_scopes(user_id: str) -> set:
|
||||
return OAUTH2_DEFAULT_SCOPES | set(
|
||||
scope_to_list(
|
||||
dyn.collection.get_item(
|
||||
KeyPair(
|
||||
pk=sub,
|
||||
pk=user_id,
|
||||
sk=SortKey(sk='SCOPE', path_spec='scope'),
|
||||
),
|
||||
exc_cls=BadRequestError,
|
||||
raise_on_error=False,
|
||||
default='',
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class InvalidSession(BadRequestError): ...
|
||||
|
||||
@@ -88,7 +88,9 @@ def _create_user(*, user: User, password: str):
|
||||
item={
|
||||
'sk': '0',
|
||||
'email_verified': False,
|
||||
'created_at': now_,
|
||||
'createdDate': now_,
|
||||
# Post-migration (users): uncomment the folloing line
|
||||
# 'created_at': now_,
|
||||
}
|
||||
| asdict(user),
|
||||
)
|
||||
@@ -116,6 +118,7 @@ def _create_user(*, user: User, password: str):
|
||||
# Post-migration (users): rename `cpf` to `CPF`
|
||||
'id': 'cpf',
|
||||
'sk': user.cpf,
|
||||
'user_id': user.id,
|
||||
'created_at': now_,
|
||||
},
|
||||
cond_expr='attribute_not_exists(sk)',
|
||||
@@ -126,6 +129,7 @@ def _create_user(*, user: User, password: str):
|
||||
# Post-migration (users): rename `email` to `EMAIL`
|
||||
'id': 'email',
|
||||
'sk': user.email,
|
||||
'user_id': user.id,
|
||||
'created_at': now_,
|
||||
},
|
||||
cond_expr='attribute_not_exists(sk)',
|
||||
|
||||
@@ -68,9 +68,9 @@ def test_forbidden(
|
||||
method=HTTPMethod.GET,
|
||||
query_string_parameters={
|
||||
'response_type': 'code',
|
||||
'client_id': '6ebe1709-0831-455c-84c0-d4c753bf33c6',
|
||||
'client_id': '5e90c38f-f058-4e16-91fa-952554a290c5',
|
||||
'redirect_uri': 'https://localhost/callback',
|
||||
'scope': 'openid email offline_access',
|
||||
'scope': 'apps:admin',
|
||||
'nonce': '123',
|
||||
'state': '456',
|
||||
},
|
||||
@@ -110,4 +110,4 @@ def test_invalid_session(
|
||||
lambda_context,
|
||||
)
|
||||
|
||||
assert r['statusCode'] == HTTPStatus.BAD_REQUEST
|
||||
assert r['statusCode'] == HTTPStatus.NOT_FOUND
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
{"id": "OAUTH2", "sk": "CLIENT_ID#8c5e92b0-9ed4-451e-8935-66084d8544b1", "client_secret": "1nFD8alDbGHgc3g1RLY960xyRJVee0SlMoIB0MUlSuiJy28W", "name": "pytest 1", "scope": "openid profile", "redirect_uris": ["https://localhost/callback"], "response_types": ["code"], "grant_types": ["authorization_code", "refresh_token"], "scope": "openid profile email offline_access apps:admin", "token_endpoint_auth_method": "none"}
|
||||
{"id": "OAUTH2", "sk": "CLIENT_ID#6ebe1709-0831-455c-84c0-d4c753bf33c6", "client_secret": "1nFD8alDbGHgc3g1RLY960xyRJVee0SlMoIB0MUlSuiJy28W", "name": "pytest 2", "scope": "openid profile", "redirect_uris": ["https://localhost/callback"], "response_types": ["code"], "grant_types": ["authorization_code", "refresh_token"], "scope": "openid profile email offline_access", "token_endpoint_auth_method": "none"}
|
||||
{"id": "OAUTH2", "sk": "CLIENT_ID#1db63660-063d-4280-b2ea-388aca4a9459", "client_secret": "1nFD8alDbGHgc3g1RLY960xyRJVee0SlMoIB0MUlSuiJy28W", "name": "pytest 3", "scope": "openid profile", "redirect_uris": ["https://localhost/callback"], "response_types": ["code"], "grant_types": ["authorization_code", "refresh_token"], "scope": "openid profile email offline_access apps:admin", "token_endpoint_auth_method": "client_secret_basic"}
|
||||
{"id": "OAUTH2", "sk": "CLIENT_ID#5e90c38f-f058-4e16-91fa-952554a290c5", "client_secret": "1nFD8alDbGHgc3g1RLY960xyRJVee0SlMoIB0MUlSuiJy28W", "name": "pytest 2", "scope": "openid profile", "redirect_uris": ["https://localhost/callback"], "response_types": ["code"], "grant_types": ["authorization_code", "refresh_token"], "scope": "apps:studio", "token_endpoint_auth_method": "none"}
|
||||
{"id": "OAUTH2#CODE", "sk": "CODE#kyqp3oSuRFTfuBaCmq3XOgGWg67l42Kt3D6xPEj7Yd3MLdi9", "client_id": "d72d4005-1fa7-4430-9754-80d5e2487bb6", "redirect_uri": "https://localhost/callback", "user_id": "357db1c5-7442-4075-98a3-fbe5c938a419", "nonce": null, "scope": "openid profile email apps:admins", "response_type": "code", "code_challenge": "ejYEIGKQUgMnNh4eV0sftb0hXdLwkvKm6OHXRYvC--I", "code_challenge_method": "S256", "created_at": "2025-08-07T12:38:26.550431-03:00"}
|
||||
|
||||
{"id": "OAUTH2#TOKEN", "sk": "REFRESH_TOKEN#CyF3Ik3b9hMIo3REVv27gZAHd7dvwZq6QrkhWr7qHEen4UVy", "client_id": "d72d4005-1fa7-4430-9754-80d5e2487bb6", "token_type": "Bearer", "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6ImF0K2p3dCIsImtpZCI6IlRjT0VuV3JGSUFEYlZJNjJlY1pzU28ydEI1eW5mbkZZNTZ0Uy05b0stNW8ifQ.eyJpc3MiOiJodHRwOi8vbG9jYWxob3N0IiwiZXhwIjoxNzU5NTg2NzgzLCJjbGllbnRfaWQiOiJkNzJkNDAwNS0xZmE3LTQ0MzAtOTc1NC04MGQ1ZTI0ODdiYjYiLCJpYXQiOjE3NTg5ODE5ODMsImp0aSI6Ik9uVzRIZm1FdFl2a21CbE4iLCJzY29wZSI6Im9wZW5pZCBwcm9maWxlIGVtYWlsIHJlYWQ6dXNlcnMiLCJzdWIiOiIzNTdkYjFjNS03NDQyLTQwNzUtOThhMy1mYmU1YzkzOGE0MTkiLCJhdWQiOiJkNzJkNDAwNS0xZmE3LTQ0MzAtOTc1NC04MGQ1ZTI0ODdiYjYifQ.i0NVgvPuf5jvl8JcYNsVCzjVUTDLihgQO4LmLeNijx9Ed3p_EgtVtcHFWFvEebe_LwTuDDtIJveH22Piyp4zresNSc_YNumnuvoY1aNd0ic2RIEtXaklRroq0xHwL_IVT-Dt6P9xL5Hyygx47Pvmci4U3wWK32a6Sb1Mm7ZZgXA00xWI1bJ_zwxFLvDkHDp9nrAa_vEWN6zRBcWc7JYNsgiaPMC0DoL8it0k48_g44zfsjGAZLcWFMoPlYt3wIcQQDeCKMsSJI0VPnqKK0pq4OOVs-pjkMyAU5aEMPvVOwdAL3VZY16RXt3eTzsmMH1XoRdCMP6UAx4ZS10RLGUPeA", "scope": "openid profile email read:users", "user": {"id": "357db1c5-7442-4075-98a3-fbe5c938a419", "name": "S\u00e9rgio R Siqueira", "email": "sergio@somosbeta.com.br", "email_verified": false}, "expires_in": 180, "issued_at": 1758981984, "ttl": 1759586784}
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
} from './ui/dropdown-menu'
|
||||
|
||||
type NavItem = {
|
||||
appId: string
|
||||
title: string
|
||||
url: string
|
||||
icon: LucideIcon
|
||||
@@ -34,23 +35,27 @@ type NavItem = {
|
||||
|
||||
const apps: NavItem[] = [
|
||||
{
|
||||
appId: 'saladeaula',
|
||||
title: 'Sala de aula',
|
||||
url: '//scorm.eduseg.workers.dev',
|
||||
icon: GraduationCapIcon
|
||||
},
|
||||
{
|
||||
appId: 'admin',
|
||||
title: 'Administrador',
|
||||
url: '//admin.saladeaula.digital',
|
||||
icon: LayoutDashboardIcon,
|
||||
scope: ['apps:admin']
|
||||
},
|
||||
{
|
||||
appId: 'studio',
|
||||
title: 'EDUSEG® Estúdio',
|
||||
url: '//studio.saladeaula.digital',
|
||||
icon: CirclePlayIcon,
|
||||
scope: ['apps:studio']
|
||||
},
|
||||
{
|
||||
appId: 'insights',
|
||||
title: 'EDUSEG® Insights',
|
||||
url: '//insights.saladeaula.digital',
|
||||
icon: LightbulbIcon,
|
||||
@@ -59,13 +64,15 @@ const apps: NavItem[] = [
|
||||
]
|
||||
|
||||
export function NavUser({
|
||||
user
|
||||
user,
|
||||
excludeApps
|
||||
}: {
|
||||
user: {
|
||||
name: string
|
||||
email: string
|
||||
scope: string
|
||||
}
|
||||
excludeApps: string[]
|
||||
}) {
|
||||
const userScope = user.scope.split(' ')
|
||||
|
||||
@@ -135,10 +142,12 @@ export function NavUser({
|
||||
</>
|
||||
)}
|
||||
|
||||
{apps.map(({ title, url, scope = [], icon: Icon }, idx) => {
|
||||
{apps
|
||||
.filter(({ appId }) => !excludeApps.includes(appId))
|
||||
.map(({ appId, title, url, scope = [], icon: Icon }) => {
|
||||
if (grantIfHas(scope, userScope)) {
|
||||
return (
|
||||
<DropdownMenuItem key={idx} asChild>
|
||||
<DropdownMenuItem key={appId} asChild>
|
||||
<Link to={url} className="cursor-pointer">
|
||||
<Icon /> {title}
|
||||
</Link>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"strict": true,
|
||||
"lib": ["DOM", "DOM.Iterable", "ES2022"],
|
||||
"types": ["vite/client"],
|
||||
|
||||
@@ -132,9 +132,10 @@ def _create_user(rawuser: dict, context: dict) -> None:
|
||||
'sk': '0',
|
||||
'email_verified': False,
|
||||
'tenant_id': {org.id},
|
||||
# Post-migration: uncomment the folloing line
|
||||
# Post-migration (users): uncomment the folloing line
|
||||
# 'org_id': {org.id},
|
||||
'created_at': now_,
|
||||
# 'created_at': now_,
|
||||
'createDate': now_,
|
||||
},
|
||||
)
|
||||
transact.put(
|
||||
@@ -147,7 +148,7 @@ def _create_user(rawuser: dict, context: dict) -> None:
|
||||
transact.put(
|
||||
item={
|
||||
'id': user_id,
|
||||
# Post-migration: rename `emails` to `EMAIL`
|
||||
# Post-migration (users): rename `emails` to `EMAIL`
|
||||
'sk': f'emails#{user.email}',
|
||||
'email_verified': False,
|
||||
'email_primary': True,
|
||||
@@ -169,9 +170,10 @@ def _create_user(rawuser: dict, context: dict) -> None:
|
||||
)
|
||||
transact.put(
|
||||
item={
|
||||
# Post-migration: rename `cpf` to `CPF`
|
||||
# Post-migration (users): rename `cpf` to `CPF`
|
||||
'id': 'cpf',
|
||||
'sk': user.cpf,
|
||||
'user_id': user_id,
|
||||
'created_at': now_,
|
||||
},
|
||||
cond_expr='attribute_not_exists(sk)',
|
||||
@@ -179,9 +181,10 @@ def _create_user(rawuser: dict, context: dict) -> None:
|
||||
)
|
||||
transact.put(
|
||||
item={
|
||||
# Post-migration: rename `email` to `EMAIL`
|
||||
# Post-migration (users): rename `email` to `EMAIL`
|
||||
'id': 'email',
|
||||
'sk': user.email,
|
||||
'user_id': user_id,
|
||||
'created_at': now_,
|
||||
},
|
||||
cond_expr='attribute_not_exists(sk)',
|
||||
@@ -191,7 +194,7 @@ def _create_user(rawuser: dict, context: dict) -> None:
|
||||
item={
|
||||
'id': user_id,
|
||||
'sk': f'orgs#{org.id}',
|
||||
# Post-migration: uncomment the following line
|
||||
# Post-migration (users): uncomment the following line
|
||||
# pk=f'ORG#{org.id}',
|
||||
'name': org.name,
|
||||
'cnpj': org.cnpj,
|
||||
@@ -201,7 +204,7 @@ def _create_user(rawuser: dict, context: dict) -> None:
|
||||
transact.put(
|
||||
item={
|
||||
'id': f'orgmembers#{org.id}',
|
||||
# Post-migration: uncomment the following line
|
||||
# Post-migration (users): uncomment the following line
|
||||
# pk=f'MEMBER#ORG#{org_id}',
|
||||
'sk': user_id,
|
||||
'created_at': now_,
|
||||
|
||||
Reference in New Issue
Block a user