diff --git a/api.saladeaula.digital/app/routes/orgs/users/__init__.py b/api.saladeaula.digital/app/routes/orgs/users/__init__.py
index 340579a..dea4cba 100644
--- a/api.saladeaula.digital/app/routes/orgs/users/__init__.py
+++ b/api.saladeaula.digital/app/routes/orgs/users/__init__.py
@@ -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_,
diff --git a/api.saladeaula.digital/app/routes/users/__init__.py b/api.saladeaula.digital/app/routes/users/__init__.py
index dfe4a0a..04cb750 100644
--- a/api.saladeaula.digital/app/routes/users/__init__.py
+++ b/api.saladeaula.digital/app/routes/users/__init__.py
@@ -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'),
),
)
diff --git a/apps/admin.saladeaula.digital/app/routes/_.$orgid.users.$id/route.tsx b/apps/admin.saladeaula.digital/app/routes/_.$orgid.users.$id/route.tsx
index fab0996..51b881d 100644
--- a/apps/admin.saladeaula.digital/app/routes/_.$orgid.users.$id/route.tsx
+++ b/apps/admin.saladeaula.digital/app/routes/_.$orgid.users.$id/route.tsx
@@ -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 })
}
diff --git a/apps/admin.saladeaula.digital/app/routes/_.$orgid/route.tsx b/apps/admin.saladeaula.digital/app/routes/_.$orgid/route.tsx
index 0cca3e7..67573e1 100644
--- a/apps/admin.saladeaula.digital/app/routes/_.$orgid/route.tsx
+++ b/apps/admin.saladeaula.digital/app/routes/_.$orgid/route.tsx
@@ -81,7 +81,7 @@ export default function Route({ loaderData }: Route.ComponentProps) {
-
+
diff --git a/apps/id.saladeaula.digital/app/routes/index.tsx b/apps/id.saladeaula.digital/app/routes/index.tsx
index 8522093..3ce99bb 100644
--- a/apps/id.saladeaula.digital/app/routes/index.tsx
+++ b/apps/id.saladeaula.digital/app/routes/index.tsx
@@ -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) => {
diff --git a/apps/id.saladeaula.digital/app/routes/register/index.tsx b/apps/id.saladeaula.digital/app/routes/register/index.tsx
index 1875c07..491ccdd 100644
--- a/apps/id.saladeaula.digital/app/routes/register/index.tsx
+++ b/apps/id.saladeaula.digital/app/routes/register/index.tsx
@@ -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(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 (
{user ? (
diff --git a/apps/id.saladeaula.digital/tsconfig.json b/apps/id.saladeaula.digital/tsconfig.json
index 97b786f..41fd9b8 100644
--- a/apps/id.saladeaula.digital/tsconfig.json
+++ b/apps/id.saladeaula.digital/tsconfig.json
@@ -6,6 +6,7 @@
],
"compilerOptions": {
"checkJs": true,
+ "moduleResolution": "bundler",
"verbatimModuleSyntax": true,
"skipLibCheck": true,
"strict": true,
diff --git a/apps/insights.saladeaula.digital/app/routes/_app/route.tsx b/apps/insights.saladeaula.digital/app/routes/_app/route.tsx
index d9df58d..3127e27 100644
--- a/apps/insights.saladeaula.digital/app/routes/_app/route.tsx
+++ b/apps/insights.saladeaula.digital/app/routes/_app/route.tsx
@@ -48,7 +48,7 @@ export default function Route({ loaderData }: Route.ComponentProps) {
-
+
diff --git a/apps/saladeaula.digital/app/routes/index.tsx b/apps/saladeaula.digital/app/routes/index.tsx
index 2ad91ea..ab27cd7 100644
--- a/apps/saladeaula.digital/app/routes/index.tsx
+++ b/apps/saladeaula.digital/app/routes/index.tsx
@@ -176,10 +176,22 @@ function List({ s, hits = [] }: { s: string; hits: Enrollment[] }) {
- Nada encontrado
-
- Nenhum resultado para {s}.
-
+ {s ? (
+ <>
+ Nada encontrado
+
+ Nenhum resultado para {s}.
+
+ >
+ ) : (
+ <>
+ Nenhum curso ainda
+
+ Comece escolhendo um curso. Assim que você se matricular, ele
+ aparecerá aqui.
+
+ >
+ )}
)
diff --git a/apps/saladeaula.digital/app/routes/layout.tsx b/apps/saladeaula.digital/app/routes/layout.tsx
index ef14776..7f8eb58 100644
--- a/apps/saladeaula.digital/app/routes/layout.tsx
+++ b/apps/saladeaula.digital/app/routes/layout.tsx
@@ -141,7 +141,7 @@ export default function Component({
-
+
diff --git a/apps/studio.saladeaula.digital/app/routes/layout.tsx b/apps/studio.saladeaula.digital/app/routes/layout.tsx
index 623be93..3264b77 100644
--- a/apps/studio.saladeaula.digital/app/routes/layout.tsx
+++ b/apps/studio.saladeaula.digital/app/routes/layout.tsx
@@ -32,7 +32,7 @@ export default function Component({ loaderData }: Route.ComponentProps) {
-
+
diff --git a/id.saladeaula.digital/app/config.py b/id.saladeaula.digital/app/config.py
index 81c299e..13d7da2 100644
--- a/id.saladeaula.digital/app/config.py
+++ b/id.saladeaula.digital/app/config.py
@@ -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
diff --git a/id.saladeaula.digital/app/events/__init__.py b/id.saladeaula.digital/app/events/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/id.saladeaula.digital/app/oauth2.py b/id.saladeaula.digital/app/oauth2.py
index 2e1bf42..39f5ad6 100644
--- a/id.saladeaula.digital/app/oauth2.py
+++ b/id.saladeaula.digital/app/oauth2.py
@@ -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),
)
diff --git a/id.saladeaula.digital/app/routes/authorize.py b/id.saladeaula.digital/app/routes/authorize.py
index 7df328c..c11731a 100644
--- a/id.saladeaula.digital/app/routes/authorize.py
+++ b/id.saladeaula.digital/app/routes/authorize.py
@@ -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): ...
diff --git a/id.saladeaula.digital/app/routes/register.py b/id.saladeaula.digital/app/routes/register.py
index de0c568..d20961b 100644
--- a/id.saladeaula.digital/app/routes/register.py
+++ b/id.saladeaula.digital/app/routes/register.py
@@ -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)',
diff --git a/id.saladeaula.digital/tests/routes/test_authorize.py b/id.saladeaula.digital/tests/routes/test_authorize.py
index e444917..928afae 100644
--- a/id.saladeaula.digital/tests/routes/test_authorize.py
+++ b/id.saladeaula.digital/tests/routes/test_authorize.py
@@ -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
diff --git a/id.saladeaula.digital/tests/seeds.jsonl b/id.saladeaula.digital/tests/seeds.jsonl
index ef18ea3..d05c740 100644
--- a/id.saladeaula.digital/tests/seeds.jsonl
+++ b/id.saladeaula.digital/tests/seeds.jsonl
@@ -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}
diff --git a/packages/ui/src/components/nav-user.tsx b/packages/ui/src/components/nav-user.tsx
index 2ddeb45..c057e07 100644
--- a/packages/ui/src/components/nav-user.tsx
+++ b/packages/ui/src/components/nav-user.tsx
@@ -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,19 +142,21 @@ export function NavUser({
>
)}
- {apps.map(({ title, url, scope = [], icon: Icon }, idx) => {
- if (grantIfHas(scope, userScope)) {
- return (
-
-
- {title}
-
-
- )
- }
+ {apps
+ .filter(({ appId }) => !excludeApps.includes(appId))
+ .map(({ appId, title, url, scope = [], icon: Icon }) => {
+ if (grantIfHas(scope, userScope)) {
+ return (
+
+
+ {title}
+
+
+ )
+ }
- return <>>
- })}
+ return <>>
+ })}
diff --git a/packages/ui/tsconfig.json b/packages/ui/tsconfig.json
index 7cf3e44..5141d5a 100644
--- a/packages/ui/tsconfig.json
+++ b/packages/ui/tsconfig.json
@@ -1,6 +1,8 @@
{
"compilerOptions": {
"composite": true,
+ "declaration": true,
+ "declarationMap": true,
"strict": true,
"lib": ["DOM", "DOM.Iterable", "ES2022"],
"types": ["vite/client"],
diff --git a/users-events/app/events/batch/chunks_into_users.py b/users-events/app/events/batch/chunks_into_users.py
index 482474f..c3fb1ff 100644
--- a/users-events/app/events/batch/chunks_into_users.py
+++ b/users-events/app/events/batch/chunks_into_users.py
@@ -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_,