diff --git a/api.saladeaula.digital/app/app.py b/api.saladeaula.digital/app/app.py index ffb5932..77fede8 100644 --- a/api.saladeaula.digital/app/app.py +++ b/api.saladeaula.digital/app/app.py @@ -50,6 +50,7 @@ app.include_router(users.password, prefix='/users') app.include_router(orders.router, prefix='/orders') app.include_router(orders.checkout, prefix='/orders') app.include_router(orders.payment_retries, prefix='/orders') +app.include_router(orgs.router, prefix='/orgs') app.include_router(orgs.add, prefix='/orgs') app.include_router(orgs.address, prefix='/orgs') app.include_router(orgs.admins, prefix='/orgs') diff --git a/api.saladeaula.digital/app/exceptions.py b/api.saladeaula.digital/app/exceptions.py index 07a76b1..aae7511 100644 --- a/api.saladeaula.digital/app/exceptions.py +++ b/api.saladeaula.digital/app/exceptions.py @@ -38,6 +38,9 @@ class UserConflictError(ConflictError): ... class EmailConflictError(ConflictError): ... +class CNPJConflictError(ConflictError): ... + + class CPFConflictError(ConflictError): ... diff --git a/api.saladeaula.digital/app/routes/enrollments/scorm.py b/api.saladeaula.digital/app/routes/enrollments/scorm.py index 6130c33..7f927b9 100644 --- a/api.saladeaula.digital/app/routes/enrollments/scorm.py +++ b/api.saladeaula.digital/app/routes/enrollments/scorm.py @@ -29,7 +29,10 @@ def get_scorm(enrollment_id: str): if not enrollment: raise NotFoundError('Enrollment not found') - spec = {'id': 'course.id', 'scormset': 'course.scormset'} + spec = { + 'id': 'course.id', + 'scormset': 'course.scormset', + } course_id, scormset_id = glom(enrollment, spec).values() scormset = dyn.collection.get_item( KeyPair(course_id, f'SCORMSET#{scormset_id}'), diff --git a/api.saladeaula.digital/app/routes/orgs/__init__.py b/api.saladeaula.digital/app/routes/orgs/__init__.py index d2056a0..c7e1589 100644 --- a/api.saladeaula.digital/app/routes/orgs/__init__.py +++ b/api.saladeaula.digital/app/routes/orgs/__init__.py @@ -1,3 +1,10 @@ +from aws_lambda_powertools import Logger +from aws_lambda_powertools.event_handler.api_gateway import Router +from layercake.dynamodb import DynamoDBPersistenceLayer, SortKey, TransactKey + +from boto3clients import dynamodb_client +from config import USER_TABLE + from .add import router as add from .address import router as address from .admins import router as admins @@ -23,3 +30,18 @@ __all__ = [ 'users', 'batch_jobs', ] + + +logger = Logger(__name__) +router = Router() +dyn = DynamoDBPersistenceLayer(USER_TABLE, dynamodb_client) + + +@router.get('/') +def get_org(org_id: str): + return dyn.collection.get_items( + TransactKey(org_id) + + SortKey('0') + + SortKey('METADATA#ADDRESS', rename_key='address') + + SortKey('METADATA#SUBSCRIPTION', rename_key='subscription') + ) diff --git a/api.saladeaula.digital/app/routes/orgs/add.py b/api.saladeaula.digital/app/routes/orgs/add.py index 69005fe..e3865c2 100644 --- a/api.saladeaula.digital/app/routes/orgs/add.py +++ b/api.saladeaula.digital/app/routes/orgs/add.py @@ -3,7 +3,6 @@ from typing import Annotated from uuid import uuid4 from aws_lambda_powertools.event_handler.api_gateway import Router -from aws_lambda_powertools.event_handler.exceptions import NotFoundError from aws_lambda_powertools.event_handler.openapi.params import Body from layercake.dateutils import now from layercake.dynamodb import DynamoDBPersistenceLayer, KeyPair @@ -13,24 +12,17 @@ from pydantic import UUID4, BaseModel, EmailStr from api_gateway import JSONResponse from boto3clients import dynamodb_client from config import INTERNAL_EMAIL_DOMAIN, USER_TABLE -from exceptions import ConflictError +from exceptions import ( + CNPJConflictError, + EmailConflictError, + EmailNotFoundError, + UserNotFoundError, +) router = Router() dyn = DynamoDBPersistenceLayer(USER_TABLE, dynamodb_client) -class CNPJConflictError(ConflictError): ... - - -class EmailConflictError(ConflictError): ... - - -class UserNotFoundError(NotFoundError): ... - - -class EmailNotFoundError(NotFoundError): ... - - class User(BaseModel): id: str | UUID4 name: NameStr @@ -101,6 +93,14 @@ def add( 'created_at': now_, } ) + transact.put( + item={ + # Post-migration (users): rename `orgmembers#` to `MEMBER#ORG#` + 'id': f'orgmembers#{org_id}', + 'sk': user.id, + 'created_at': now_, + } + ) transact.put( item={ 'id': user.id, @@ -119,14 +119,6 @@ def add( 'created_at': now_, } ) - transact.put( - item={ - # Post-migration (users): rename `orgmembers#` to `MEMBER#ORG#` - 'id': f'orgmembers#{org_id}', - 'sk': user.id, - 'created_at': now_, - } - ) transact.condition( key=KeyPair(str(user.id), '0'), cond_expr='attribute_exists(sk)', diff --git a/api.saladeaula.digital/app/routes/orgs/address.py b/api.saladeaula.digital/app/routes/orgs/address.py index 9f806ff..8228e96 100644 --- a/api.saladeaula.digital/app/routes/orgs/address.py +++ b/api.saladeaula.digital/app/routes/orgs/address.py @@ -16,15 +16,6 @@ router = Router() dyn = DynamoDBPersistenceLayer(USER_TABLE, dynamodb_client) -@router.get('//address') -def address(org_id: str): - return dyn.collection.get_item( - KeyPair(org_id, 'METADATA#ADDRESS'), - raise_on_error=False, - default={}, - ) - - class Address(BaseModel): model_config = ConfigDict(str_strip_whitespace=True) diff --git a/api.saladeaula.digital/app/routes/orgs/subscription.py b/api.saladeaula.digital/app/routes/orgs/subscription.py index c07341a..fc7123d 100644 --- a/api.saladeaula.digital/app/routes/orgs/subscription.py +++ b/api.saladeaula.digital/app/routes/orgs/subscription.py @@ -22,18 +22,6 @@ class PaymentMethod(str, Enum): MANUAL = 'MANUAL' -@router.get('//subscription') -def subscription(org_id: str): - return dyn.collection.get_item( - KeyPair( - pk=org_id, - sk='METADATA#SUBSCRIPTION', - ), - raise_on_error=False, - default={}, - ) - - @router.post('//subscription') def add( org_id: str, @@ -44,8 +32,13 @@ def add( now_ = now() with dyn.transact_writer() as transact: - transact.condition( + transact.update( key=KeyPair(org_id, '0'), + update_expr='SET subscription_covered = :true, updated_at = :now', + expr_attr_values={ + ':true': True, + ':now': now_, + }, cond_expr='attribute_exists(sk)', exc_cls=OrgNotFoundError, ) diff --git a/api.saladeaula.digital/app/routes/users/__init__.py b/api.saladeaula.digital/app/routes/users/__init__.py index 04cb750..5a8fbc5 100644 --- a/api.saladeaula.digital/app/routes/users/__init__.py +++ b/api.saladeaula.digital/app/routes/users/__init__.py @@ -3,7 +3,6 @@ from typing import Annotated from aws_lambda_powertools.event_handler.api_gateway import Router from aws_lambda_powertools.event_handler.exceptions import ( - NotFoundError, ServiceError, ) from aws_lambda_powertools.event_handler.openapi.params import Body @@ -19,6 +18,7 @@ from layercake.extra_types import CpfStr, NameStr from api_gateway import JSONResponse from boto3clients import dynamodb_client from config import USER_TABLE +from exceptions import CPFConflictError, UserNotFoundError from .emails import router as emails from .orgs import router as orgs @@ -30,14 +30,6 @@ router = Router() dyn = DynamoDBPersistenceLayer(USER_TABLE, dynamodb_client) -class UserNotFoundError(NotFoundError): ... - - -class CPFConflictError(ServiceError): - def __init__(self, msg: str | dict): - super().__init__(HTTPStatus.CONFLICT, msg) - - class RateLimitExceededError(ServiceError): def __init__(self, msg: str | dict): super().__init__(HTTPStatus.TOO_MANY_REQUESTS, msg) diff --git a/apps/admin.saladeaula.digital/app/components/workspace-switcher.tsx b/apps/admin.saladeaula.digital/app/components/workspace-switcher.tsx index 35c1b0f..9ea7ca1 100644 --- a/apps/admin.saladeaula.digital/app/components/workspace-switcher.tsx +++ b/apps/admin.saladeaula.digital/app/components/workspace-switcher.tsx @@ -75,9 +75,9 @@ export function WorkspaceSwitcher() { className="aria-expanded:border flex aspect-square size-8 items-center justify-center rounded-lg relative" aria-expanded={state === 'expanded'} > - {subscription && ( + {subscription ? ( - )} + ) : null} {initials(activeWorkspace.name)} diff --git a/apps/admin.saladeaula.digital/app/middleware/workspace.ts b/apps/admin.saladeaula.digital/app/middleware/workspace.ts index 9a23e12..9c69f20 100644 --- a/apps/admin.saladeaula.digital/app/middleware/workspace.ts +++ b/apps/admin.saladeaula.digital/app/middleware/workspace.ts @@ -53,33 +53,18 @@ export const workspaceMiddleware = async ( ({ id }) => id === org_id ) as Workspace - const [subscription, address] = await Promise.all([ - req({ - url: `/orgs/${activeWorkspace.id}/subscription`, - request, - context - }) - .then((r) => r.json()) - .then(emptyObjectToNull), - - req({ - url: `/orgs/${activeWorkspace.id}/address`, - request, - context - }) - .then((r) => r.json()) - .then(emptyObjectToNull) - ]) + const org = (await req({ + url: `/orgs/${activeWorkspace.id}`, + request, + context + }).then((r) => r.json())) as any context.set(workspaceContext, { activeWorkspace, workspaces, - subscription, - address + subscription: org?.['subscription'] || null, + address: org?.['address'] || null }) return await next() } - -const emptyObjectToNull = (data: any) => - data && Object.keys(data).length === 0 ? null : data diff --git a/apps/admin.saladeaula.digital/app/routes/_.$orgid.billing._index/route.tsx b/apps/admin.saladeaula.digital/app/routes/_.$orgid.billing._index/route.tsx index 4da4817..b08a9bd 100644 --- a/apps/admin.saladeaula.digital/app/routes/_.$orgid.billing._index/route.tsx +++ b/apps/admin.saladeaula.digital/app/routes/_.$orgid.billing._index/route.tsx @@ -34,6 +34,7 @@ import { cn } from '@repo/ui/lib/utils' import { request as req } from '@repo/util/request' import { TZ } from '@/conf' +import { workspaceContext } from '@/middleware/workspace' import { statuses } from './data' import { RangePeriod } from './range-period' import { billingPeriod, formatDate } from './util' @@ -43,16 +44,9 @@ export function meta({}) { } export async function loader({ context, request, params }: Route.LoaderArgs) { + const workspace = context.get(workspaceContext) const { searchParams } = new URL(request.url) - const subscription = await req({ - url: `/orgs/${params.orgid}/subscription`, - context, - request - }) - - const { billing_day = 1 } = (await subscription.json()) as { - billing_day: number - } + const { billing_day = 1 } = workspace?.subscription || {} const [startDate, endDate] = billingPeriod( billing_day, diff --git a/apps/admin.saladeaula.digital/app/routes/_.$orgid.payments.$id._index/route.tsx b/apps/admin.saladeaula.digital/app/routes/_.$orgid.payments.$id._index/route.tsx index 0f46bfe..6227216 100644 --- a/apps/admin.saladeaula.digital/app/routes/_.$orgid.payments.$id._index/route.tsx +++ b/apps/admin.saladeaula.digital/app/routes/_.$orgid.payments.$id._index/route.tsx @@ -9,6 +9,7 @@ import { CircleCheckIcon, CircleXIcon, EllipsisIcon, + ExternalLinkIcon, HelpCircleIcon } from 'lucide-react' import { useEffect } from 'react' @@ -355,9 +356,14 @@ function BankSlipPaymentMethod({ {invoice?.bank_slip ? ( <> - diff --git a/apps/admin.saladeaula.digital/app/routes/_.$orgid.users.$id._index/route.tsx b/apps/admin.saladeaula.digital/app/routes/_.$orgid.users.$id._index/route.tsx index 32b8a5a..cbe1f69 100644 --- a/apps/admin.saladeaula.digital/app/routes/_.$orgid.users.$id._index/route.tsx +++ b/apps/admin.saladeaula.digital/app/routes/_.$orgid.users.$id._index/route.tsx @@ -1,13 +1,18 @@ import type { Route } from './+types/route' -import { useEffect } from 'react' import { zodResolver } from '@hookform/resolvers/zod' -import { PatternFormat } from 'react-number-format' -import { useFetcher, Link, useOutletContext } from 'react-router' import { AlertCircleIcon } from 'lucide-react' +import { useEffect } from 'react' import { useForm } from 'react-hook-form' +import { PatternFormat } from 'react-number-format' +import { Link, useFetcher, useOutletContext } from 'react-router' import { toast } from 'sonner' +import { + Alert, + AlertDescription, + AlertTitle +} from '@repo/ui/components/ui/alert' import { Button } from '@repo/ui/components/ui/button' import { Card, @@ -27,13 +32,9 @@ import { import { Input } from '@repo/ui/components/ui/input' import { Spinner } from '@repo/ui/components/ui/spinner' import { type User } from '@repo/ui/routes/users/data' -import { - Alert, - AlertDescription, - AlertTitle -} from '@repo/ui/components/ui/alert' -import { request as req, HttpMethod } from '@repo/util/request' +import { HttpMethod, request as req } from '@repo/util/request' +import { FieldSet } from '@repo/ui/components/ui/field' import { formSchema, type Schema } from '../_.$orgid.users.add/data' export async function action({ params, request, context }: Route.ActionArgs) { @@ -109,80 +110,84 @@ export default function Route({}: Route.ComponentProps) { - - ( - - Nome - - - - - - )} - /> + +
+ ( + + Nome + + + + + + )} + /> - ( - - Email - - - - - - Para gerenciar os emails ou trocar o email principal, - use as{' '} - - configurações de emails - - - - - - )} - /> + ( + + Email + + + + + + Para gerenciar os emails ou trocar o email principal, + use as{' '} + + configurações de emails + + + + + + )} + /> - ( - - CPF - - { - onChange(value) - }} - {...props} - /> - - - - )} - /> + ( + + CPF + + { + onChange(value) + }} + {...props} + /> + + + + )} + /> - +
+ +
+
diff --git a/apps/admin.saladeaula.digital/app/routes/_.$orgid/route.tsx b/apps/admin.saladeaula.digital/app/routes/_.$orgid/route.tsx index 90418b0..4a6baa4 100644 --- a/apps/admin.saladeaula.digital/app/routes/_.$orgid/route.tsx +++ b/apps/admin.saladeaula.digital/app/routes/_.$orgid/route.tsx @@ -1,23 +1,23 @@ import type { Route } from './+types/route' import * as cookie from 'cookie' -import { Outlet, type ShouldRevalidateFunctionArgs } from 'react-router' import { useEffect } from 'react' +import { Outlet, type ShouldRevalidateFunctionArgs } from 'react-router' +import { userContext } from '@repo/auth/context' +import { authMiddleware } from '@repo/auth/middleware/auth' +import { ModeToggle, ThemedImage } from '@repo/ui/components/dark-mode' +import { NavUser } from '@repo/ui/components/nav-user' import { SidebarInset, SidebarProvider, SidebarTrigger } from '@repo/ui/components/ui/sidebar' -import { userContext } from '@repo/auth/context' -import { authMiddleware } from '@repo/auth/middleware/auth' import { Toaster } from '@repo/ui/components/ui/sonner' -import { ModeToggle, ThemedImage } from '@repo/ui/components/dark-mode' -import { NavUser } from '@repo/ui/components/nav-user' -import { WorkspaceProvider } from '@/components/workspace-switcher' import { AppSidebar } from '@/components/app-sidebar' -import { workspaceMiddleware, workspaceContext } from '@/middleware/workspace' +import { WorkspaceProvider } from '@/components/workspace-switcher' +import { workspaceContext, workspaceMiddleware } from '@/middleware/workspace' // import { Notification } from '@/components/notification' diff --git a/apps/insights.saladeaula.digital/app/routes/_app.enrollments._index/columns.tsx b/apps/insights.saladeaula.digital/app/routes/_app.enrollments._index/columns.tsx index 1eb86c9..fcae3df 100644 --- a/apps/insights.saladeaula.digital/app/routes/_app.enrollments._index/columns.tsx +++ b/apps/insights.saladeaula.digital/app/routes/_app.enrollments._index/columns.tsx @@ -5,18 +5,19 @@ import { useToggle } from 'ahooks' import { EllipsisIcon, FileBadgeIcon } from 'lucide-react' import type { ComponentProps } from 'react' +import { + DataTableColumnHeaderSelect, + DataTableColumnSelect +} from '@repo/ui/components/data-table/column-select' import { Button } from '@repo/ui/components/ui/button' import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, + DropdownMenuSeparator, DropdownMenuTrigger } from '@repo/ui/components/ui/dropdown-menu' import { Spinner } from '@repo/ui/components/ui/spinner' -import { - DataTableColumnHeaderSelect, - DataTableColumnSelect -} from '@repo/ui/components/data-table/column-select' import { columns as columns_, type Enrollment @@ -65,12 +66,13 @@ function ActionMenu({ row }: { row: any }) { - setOpen(false)} /> + + diff --git a/apps/insights.saladeaula.digital/app/routes/_app.orgs.$id._index/route.tsx b/apps/insights.saladeaula.digital/app/routes/_app.orgs.$id._index/route.tsx new file mode 100644 index 0000000..719ffc3 --- /dev/null +++ b/apps/insights.saladeaula.digital/app/routes/_app.orgs.$id._index/route.tsx @@ -0,0 +1,168 @@ +import type { Route } from './+types/route' + +import { useForm } from 'react-hook-form' +import { Link } from 'react-router' + +import { Avatar, AvatarFallback } from '@repo/ui/components/ui/avatar' +import { + Breadcrumb, + BreadcrumbItem, + BreadcrumbLink, + BreadcrumbList, + BreadcrumbPage, + BreadcrumbSeparator +} from '@repo/ui/components/ui/breadcrumb' +import { Button } from '@repo/ui/components/ui/button' +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle +} from '@repo/ui/components/ui/card' +import { FieldSet } from '@repo/ui/components/ui/field' +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage +} from '@repo/ui/components/ui/form' +import { Input } from '@repo/ui/components/ui/input' +import { initials } from '@repo/ui/lib/utils' +import { request as req } from '@repo/util/request' +import { BadgeCheckIcon } from 'lucide-react' + +export function meta() { + return [ + { + title: 'Editar empresa' + } + ] +} + +export async function loader({ params, request, context }: Route.LoaderArgs) { + const r = await req({ + url: `/orgs/${params.id}`, + request, + context + }) + + if (!r.ok) { + throw new Response(null, { status: r.status }) + } + + return { org: await r.json() } as { org: any } +} + +export default function Route({ loaderData: { org } }: Route.ComponentProps) { + const form = useForm({ defaultValues: org }) + const { handleSubmit } = form + + const onSubmit = async () => {} + + return ( +
+ + + + + Empresas + + + + + Editar empresa + + + + +
+
+
+ {org?.subscription ? ( + + ) : null} + + + {initials(org.name)} + +
+ +
    +
  • {org.name}
  • +
  • + {org.email} +
  • +
+
+ +
+ + + + + Editar empresa + + + Configurar as informações gerais para esta empresa. + + + + +
+ ( + + Nome + + + + + + )} + /> + + ( + + Email + + + + + + )} + /> + + ( + + CNPJ + + + + + + )} + /> + +
+ +
+
+
+
+
+ +
+
+ ) +} diff --git a/apps/insights.saladeaula.digital/app/routes/_app.orgs._index/columns.tsx b/apps/insights.saladeaula.digital/app/routes/_app.orgs._index/columns.tsx index 1203a63..6900617 100644 --- a/apps/insights.saladeaula.digital/app/routes/_app.orgs._index/columns.tsx +++ b/apps/insights.saladeaula.digital/app/routes/_app.orgs._index/columns.tsx @@ -1,23 +1,27 @@ 'use client' import { type ColumnDef } from '@tanstack/react-table' -import { EllipsisIcon } from 'lucide-react' +import { EllipsisIcon, PencilIcon } from 'lucide-react' +import { NavLink } from 'react-router' -import { Button } from '@repo/ui/components/ui/button' -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuTrigger -} from '@repo/ui/components/ui/dropdown-menu' import { Abbr } from '@repo/ui/components/abbr' -import { Avatar, AvatarFallback } from '@repo/ui/components/ui/avatar' -import { initials } from '@repo/ui/lib/utils' import { DataTableColumnCpfCnpj, DataTableColumnDatetime, DataTableColumnHeaderSelect, DataTableColumnSelect } from '@repo/ui/components/data-table' +import { Avatar, AvatarFallback } from '@repo/ui/components/ui/avatar' +import { Button } from '@repo/ui/components/ui/button' +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger +} from '@repo/ui/components/ui/dropdown-menu' +import { Spinner } from '@repo/ui/components/ui/spinner' +import { initials } from '@repo/ui/lib/utils' import type { Org } from '@repo/ui/routes/orgs/data' import { CopyToClipboardItem } from '../_app.users._index/columns' @@ -86,6 +90,17 @@ function ActionMenu({ row }: { row: any }) { + e.preventDefault()}> + + {({ isPending }) => ( + <> + {isPending ? : } + Editar + + )} + + + diff --git a/id.saladeaula.digital/tests/routes/test_authentication.py b/id.saladeaula.digital/tests/routes/test_authentication.py index 7cf8d79..ac2bec6 100644 --- a/id.saladeaula.digital/tests/routes/test_authentication.py +++ b/id.saladeaula.digital/tests/routes/test_authentication.py @@ -53,7 +53,7 @@ def test_invalid_password( assert r['statusCode'] == HTTPStatus.UNAUTHORIZED failed = dynamodb_persistence_layer.collection.get_item( - KeyPair('357db1c5-7442-4075-98a3-fbe5c938a419', 'FAILED_ATTEMPTS') + KeyPair('357db1c5-7442-4075-98a3-fbe5c938a419', 'LOGIN#FAILED_ATTEMPTS') ) assert 'failed_attempts' in failed diff --git a/id.saladeaula.digital/uv.lock b/id.saladeaula.digital/uv.lock index 0a3d19f..829edb2 100644 --- a/id.saladeaula.digital/uv.lock +++ b/id.saladeaula.digital/uv.lock @@ -15,6 +15,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, ] +[[package]] +name = "anyio" +version = "4.12.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685, upload-time = "2026-01-06T11:45:21.246Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" }, +] + [[package]] name = "arnparse" version = "0.0.2" @@ -266,6 +278,23 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2c/1a/aff8bb287a4b1400f69e09a53bd65de96aa5cee5691925b38731c67fc695/click_default_group-1.2.4-py2.py3-none-any.whl", hash = "sha256:9b60486923720e7fc61731bdb32b617039aba820e22e1c88766b1125592eaa5f", size = 4123, upload-time = "2023-08-04T07:54:56.875Z" }, ] +[[package]] +name = "cloudflare" +version = "4.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "distro" }, + { name = "httpx" }, + { name = "pydantic" }, + { name = "sniffio" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5d/48/e481c0a9b9010a5c41b5ca78ff9fbe00dc8a9a4d39da5af610a4ec49c7f7/cloudflare-4.3.1.tar.gz", hash = "sha256:b1e1c6beeb8d98f63bfe0a1cba874fc4e22e000bcc490544f956c689b3b5b258", size = 1933187, upload-time = "2025-06-16T21:43:18.716Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/8f/c6c543565efd3144da4304efa5917aac06b6416a8663a6defe0e9b2b7569/cloudflare-4.3.1-py3-none-any.whl", hash = "sha256:6927135a5ee5633d6e2e1952ca0484745e933727aeeb189996d2ad9d292071c6", size = 4406465, upload-time = "2025-06-16T21:43:17.3Z" }, +] + [[package]] name = "colorama" version = "0.4.6" @@ -350,6 +379,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/47/ef/4cb333825d10317a36a1154341ba37e6e9c087bac99c1990ef07ffdb376f/dictdiffer-0.9.0-py2.py3-none-any.whl", hash = "sha256:442bfc693cfcadaf46674575d2eba1c53b42f5e404218ca2c2ff549f2df56595", size = 16754, upload-time = "2021-07-22T13:24:26.783Z" }, ] +[[package]] +name = "distro" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722, upload-time = "2023-12-24T09:54:32.31Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, +] + [[package]] name = "dnspython" version = "2.7.0" @@ -419,6 +457,43 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9c/a2/75fd80784ec33da8d39cf885e8811a4fbc045a90db5e336b8e345e66dbb2/glom-24.11.0-py3-none-any.whl", hash = "sha256:991db7fcb4bfa9687010aa519b7b541bbe21111e70e58fdd2d7e34bbaa2c1fbd", size = 102690, upload-time = "2024-11-02T23:17:46.468Z" }, ] +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + [[package]] name = "id-saladeaula-digital" version = "0.1.0" @@ -513,12 +588,13 @@ wheels = [ [[package]] name = "layercake" -version = "0.11.2" +version = "0.12.0" source = { directory = "../layercake" } dependencies = [ { name = "arnparse" }, { name = "authlib" }, { name = "aws-lambda-powertools", extra = ["all"] }, + { name = "cloudflare" }, { name = "dictdiffer" }, { name = "ftfy" }, { name = "glom" }, @@ -544,6 +620,7 @@ requires-dist = [ { name = "arnparse", specifier = ">=0.0.2" }, { name = "authlib", specifier = ">=1.6.5" }, { name = "aws-lambda-powertools", extras = ["all"], specifier = ">=3.23.0" }, + { name = "cloudflare", specifier = ">=4.3.1" }, { name = "dictdiffer", specifier = ">=0.9.0" }, { name = "ftfy", specifier = ">=6.3.1" }, { name = "glom", specifier = ">=24.11.0" }, @@ -1074,6 +1151,15 @@ s3 = [ { name = "boto3" }, ] +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + [[package]] name = "sqlite-fts4" version = "1.0.3"