zrb 0.0.50__py3-none-any.whl → 0.0.52__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. zrb/action/runner.py +15 -3
  2. zrb/builtin/generator/docker_compose_task/template/_automate/snake_task_name.py +1 -1
  3. zrb/builtin/generator/fastapp/add.py +3 -2
  4. zrb/builtin/generator/fastapp/template/_automate/snake_app_name/frontend.py +17 -2
  5. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/.gitignore +2 -1
  6. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/Dockerfile +1 -1
  7. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/config.py +3 -0
  8. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/core/messagebus/rabbitmq/consumer.py +4 -1
  9. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/frontend/.gitignore +2 -2
  10. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/frontend/package-lock.json +197 -115
  11. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/frontend/package.json +7 -1
  12. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/frontend/src/app.html +1 -1
  13. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/frontend/src/lib/auth/auth.ts +83 -0
  14. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/frontend/src/lib/auth/store.ts +4 -0
  15. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/frontend/src/lib/auth/type.ts +10 -0
  16. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/frontend/src/lib/components/navigation/Menu.svelte +20 -0
  17. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/frontend/src/lib/components/navigation/Navigation.svelte +77 -0
  18. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/frontend/src/lib/components/navigation/type.ts +6 -0
  19. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/frontend/src/lib/config/config.ts +4 -0
  20. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/frontend/src/lib/config/navData.ts +25 -0
  21. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/frontend/src/lib/cookie/cookie.ts +19 -0
  22. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/frontend/src/routes/+layout.svelte +9 -6
  23. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/frontend/src/routes/greetings/[slug]/+page.js +4 -4
  24. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/frontend/src/routes/greetings/[slug]/+page.svelte +3 -7
  25. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/frontend/src/routes/sample/+page.svelte +37 -0
  26. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/frontend/src/routes/sample/delete/[id]/+page.svelte +1 -0
  27. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/frontend/static/favicon.png +0 -0
  28. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/frontend/static/logo.png +0 -0
  29. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/frontend/tailwind.config.js +1 -1
  30. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/module/auth/api.py +1 -1
  31. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/module/auth/component/authorizer.py +1 -1
  32. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/module/auth/component/token_scheme.py +1 -1
  33. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/module/auth/core/authorizer/authorizer.py +1 -1
  34. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/module/auth/core/authorizer/rpc_authorizer.py +9 -5
  35. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/module/auth/core/token_scheme/oauth2_bearer_token_scheme.py +1 -1
  36. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/module/auth/entity/user/api.py +32 -8
  37. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/module/auth/entity/user/model.py +60 -52
  38. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/module/auth/entity/user/rpc.py +23 -8
  39. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/module/auth/schema/request.py +10 -0
  40. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/template.env +4 -0
  41. zrb/builtin/generator/fastapp/template/src/kebab-app-name/test/auth/test_group_crud.py +3 -3
  42. zrb/builtin/generator/fastapp/template/src/kebab-app-name/test/auth/test_permission_crud.py +3 -3
  43. zrb/builtin/generator/fastapp/template/src/kebab-app-name/test/auth/test_user_crud.py +3 -3
  44. zrb/builtin/generator/fastapp/template/src/kebab-app-name/test/auth/test_user_login.py +12 -12
  45. zrb/builtin/generator/fastapp_crud/add.py +86 -5
  46. zrb/builtin/generator/fastapp_crud/nodejs/codemod/.gitignore +1 -0
  47. zrb/builtin/generator/fastapp_crud/nodejs/codemod/package-lock.json +317 -0
  48. zrb/builtin/generator/fastapp_crud/nodejs/codemod/package.json +18 -0
  49. zrb/builtin/generator/fastapp_crud/nodejs/codemod/src/addNav.ts +38 -0
  50. zrb/builtin/generator/fastapp_crud/nodejs/codemod/tsconfig.json +109 -0
  51. zrb/builtin/generator/fastapp_crud/template/src/kebab-app-name/test/snake_module_name/test_snake_entity_name.py +3 -3
  52. zrb/builtin/generator/project/template/.gitignore +1 -1
  53. zrb/builtin/generator/simple_python_app/template/src/kebab-app-name/src/.gitignore +1 -1
  54. zrb/task/base_task.py +3 -1
  55. zrb-0.0.52.dist-info/METADATA +605 -0
  56. {zrb-0.0.50.dist-info → zrb-0.0.52.dist-info}/RECORD +60 -44
  57. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/frontend/src/lib/components/Navigation.svelte +0 -24
  58. zrb/builtin/generator/fastapp/template/src/kebab-app-name/src/frontend/src/lib/data/navData.json +0 -5
  59. zrb-0.0.50.dist-info/METADATA +0 -450
  60. /zrb/builtin/generator/{fastapp/template/src/kebab-app-name/src/frontend/src/routes/greetings/[slug]/page.js → fastapp_crud/nodejs/codemod/src/fastapp/src/frontend/src/lib/config/navData.ts} +0 -0
  61. {zrb-0.0.50.dist-info → zrb-0.0.52.dist-info}/LICENSE +0 -0
  62. {zrb-0.0.50.dist-info → zrb-0.0.52.dist-info}/WHEEL +0 -0
  63. {zrb-0.0.50.dist-info → zrb-0.0.52.dist-info}/entry_points.txt +0 -0
@@ -36,5 +36,11 @@
36
36
  "vite": "^4.2.0",
37
37
  "vitest": "^0.25.3"
38
38
  },
39
- "type": "module"
39
+ "type": "module",
40
+ "dependencies": {
41
+ "axios": "^1.4.0",
42
+ "daisyui": "^2.51.6",
43
+ "jwt-decode": "^3.1.2",
44
+ "process": "^0.11.10"
45
+ }
40
46
  }
@@ -6,7 +6,7 @@
6
6
  <meta name="viewport" content="width=device-width" />
7
7
  %sveltekit.head%
8
8
  </head>
9
- <body data-sveltekit-preload-data="hover">
9
+ <body data-sveltekit-preload-data="hover" data-theme="emerald">
10
10
  <div style="display: contents">%sveltekit.body%</div>
11
11
  </body>
12
12
  </html>
@@ -0,0 +1,83 @@
1
+ import axios from 'axios';
2
+ import jwt_decode from 'jwt-decode';
3
+ import { appAuthTokenCookieKey } from '../config/config';
4
+ import { getCookie, setCookie, unsetCookie } from '../cookie/cookie';
5
+ import { userIdStore, userNameStore } from './store';
6
+ import type { TokenData } from './type';
7
+
8
+ export async function refreshToken(refreshTokenUrl: string): Promise<boolean> {
9
+ try {
10
+ const oldToken: string = getCookie(appAuthTokenCookieKey);
11
+ const oldTokenData: TokenData = decodeToken(oldToken);
12
+ const { expireAt } = oldTokenData;
13
+ const now = new Date();
14
+ if (now.getTime()/1000 > expireAt) {
15
+ throw new Error('Expired token');
16
+ }
17
+ const response = await axios.post(refreshTokenUrl, {token: oldToken});
18
+ if (response && response.status == 200 && response.data && response.data.access_token) {
19
+ const newToken: string = response.data.access_token;
20
+ setCookie(appAuthTokenCookieKey, newToken);
21
+ setAuthStoreByToken(newToken);
22
+ return true;
23
+ }
24
+ } catch(error) {
25
+ console.error(error);
26
+ }
27
+ logout();
28
+ return false;
29
+ }
30
+
31
+ export async function login(loginUrl: string, identity: string, password: string): Promise<boolean> {
32
+ try {
33
+ const response = await axios.post(loginUrl, {identity, password});
34
+ if (response && response.status == 200 && response.data && response.data.access_token) {
35
+ const token: string = response.data.access_token;
36
+ setCookie(appAuthTokenCookieKey, token);
37
+ setAuthStoreByToken(token);
38
+ return true;
39
+ }
40
+ } catch(error) {
41
+ console.error(error);
42
+ }
43
+ logout();
44
+ return false;
45
+ }
46
+
47
+ export function logout() {
48
+ unsetCookie(appAuthTokenCookieKey)
49
+ unsetAuthStore();
50
+ }
51
+
52
+ function unsetAuthStore() {
53
+ setAuthStore('', '');
54
+ }
55
+
56
+ function setAuthStoreByToken(token: string) {
57
+ const tokenData = decodeToken(token);
58
+ setAuthStore(tokenData.sub.userId, tokenData.sub.userName);
59
+ }
60
+
61
+ function setAuthStore(newUserId: string, newUserName: string) {
62
+ userIdStore.set(newUserId);
63
+ userNameStore.set(newUserName);
64
+ }
65
+
66
+ function decodeToken(token: string): TokenData {
67
+ const jwtTokenData: {
68
+ exp: number,
69
+ sub: {
70
+ user_id: string,
71
+ username: string,
72
+ expire_seconds: number
73
+ }
74
+ } = jwt_decode(token);
75
+ return {
76
+ sub: {
77
+ userId: jwtTokenData.sub.user_id,
78
+ userName: jwtTokenData.sub.username,
79
+ expireSeconds: jwtTokenData.sub.expire_seconds,
80
+ },
81
+ expireAt: jwtTokenData.exp
82
+ }
83
+ }
@@ -0,0 +1,4 @@
1
+ import { writable } from 'svelte/store';
2
+
3
+ export const userIdStore = writable('');
4
+ export const userNameStore = writable('');
@@ -0,0 +1,10 @@
1
+ export interface TokenData {
2
+ sub: TokenDataSub;
3
+ expireAt: number;
4
+ }
5
+
6
+ export interface TokenDataSub {
7
+ userId: string;
8
+ userName: string;
9
+ expireSeconds: number;
10
+ }
@@ -0,0 +1,20 @@
1
+ <script lang="ts">
2
+ import type {SingleNavData} from './type';
3
+ export let data: SingleNavData;
4
+ </script>
5
+ {#if 'submenus' in data && data.submenus}
6
+ <!-- svelte-ignore a11y-no-noninteractive-tabindex -->
7
+ <li tabindex="0">
8
+ <a href="#top">
9
+ Parent
10
+ <svg class="fill-current" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"><path d="M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z"/></svg>
11
+ </a>
12
+ <ul class="p-2 bg-base-100 z-10">
13
+ {#each data.submenus as submenu}
14
+ <svelte:self data={submenu} />
15
+ {/each}
16
+ </ul>
17
+ </li>
18
+ {:else}
19
+ <li><a href={data.url} class="px-4">{data.title}</a></li>
20
+ {/if}
@@ -0,0 +1,77 @@
1
+ <script lang="ts">
2
+ import { goto } from '$app/navigation';
3
+ import { onMount } from 'svelte';
4
+ import Menu from './Menu.svelte';
5
+ import type { SingleNavData } from './type';
6
+ import { login, logout, refreshToken } from '../../auth/auth';
7
+ import { userIdStore } from '../../auth/store';
8
+
9
+ export let logo: string;
10
+ export let brand: string;
11
+ export let data: SingleNavData[];
12
+ export let loginTitle: string = 'Login';
13
+ export let logoutTitle: string = 'Logout';
14
+ export let loginApiUrl: string = '/api/v1/auth/login';
15
+ export let refreshTokenApiUrl: string = '/api/v1/auth/refresh-token';
16
+
17
+ let identity: string;
18
+ let password: string;
19
+
20
+ let userId = '';
21
+ userIdStore.subscribe((value) => {
22
+ userId = value;
23
+ });
24
+
25
+ onMount(async() => {
26
+ await refreshToken(refreshTokenApiUrl);
27
+ });
28
+
29
+ async function onLoginClick() {
30
+ const loginSuccess = await login(loginApiUrl, identity, password);
31
+ if (loginSuccess) {
32
+ await goto('/');
33
+ return;
34
+ }
35
+ alert('salah');
36
+ }
37
+
38
+ async function onLogoutClick() {
39
+ logout();
40
+ await goto('/');
41
+ }
42
+ </script>
43
+
44
+ <div class="navbar sticky top-0 bg-base-100">
45
+ <div class="flex-1">
46
+ <img class="h-8 mr-3" src={logo} alt="Logo">
47
+ <a href="/" class="btn btn-ghost normal-case text-xl">{brand}</a>
48
+ </div>
49
+ <div class="flex-none">
50
+ <ul class="menu menu-horizontal px-1">
51
+ {#each data as menuData}
52
+ <Menu data={menuData} />
53
+ {/each}
54
+ {#if userId == ''}
55
+ <li><a href="#login-modal" class="px-4">{loginTitle}</a></li>
56
+ {:else}
57
+ <li><a href="#top" class="px-4" on:click={onLogoutClick}>{logoutTitle}</a></li>
58
+ {/if}
59
+ </ul>
60
+ </div>
61
+ </div>
62
+
63
+ <div class="modal" id="login-modal">
64
+ <form class="modal-box">
65
+ <div class="mb-6">
66
+ <label class="block text-gray-700 font-bold mb-2" for="identity">Identity</label>
67
+ <input class="w-full px-3 py-2 border rounded-lg text-gray-700 focus:outline-none focus:shadow-outline" id="identity" type="text" placeholder="Enter your username/email/phone" bind:value={identity} />
68
+ </div>
69
+ <div class="mb-6">
70
+ <label class="block text-gray-700 font-bold mb-2" for="password">Password</label>
71
+ <input class="w-full px-3 py-2 border rounded-lg text-gray-700 focus:outline-none focus:shadow-outline" id="password" type="password" placeholder="Enter your password" bind:value={password} />
72
+ </div>
73
+ <div class="modal-action">
74
+ <a href="#top" class="btn btn-primary" on:click={onLoginClick}>Sign in</a>
75
+ </div>
76
+ </form>
77
+ </div>
@@ -0,0 +1,6 @@
1
+ export interface SingleNavData {
2
+ url: string;
3
+ title: string;
4
+ permission?: string;
5
+ submenus?: SingleNavData[];
6
+ }
@@ -0,0 +1,4 @@
1
+ import {PUBLIC_BRAND, PUBLIC_TITLE, PUBLIC_AUTH_TOKEN_COOKIE_KEY} from '$env/static/public';
2
+ export const appBrand = PUBLIC_BRAND || 'PascalAppName';
3
+ export const appTitle = PUBLIC_TITLE || 'PascalAppName';
4
+ export const appAuthTokenCookieKey = PUBLIC_AUTH_TOKEN_COOKIE_KEY || 'auth_token';
@@ -0,0 +1,25 @@
1
+ import type { SingleNavData } from '../components/navigation/type'
2
+
3
+ export const navData: SingleNavData[] = [
4
+ {title: "Home", url: "/"},
5
+ {
6
+ title: "Auth",
7
+ url: "#",
8
+ submenus: [
9
+ {title: "Permission", url: "auth/permission"},
10
+ {title: "Group", url: "auth/group"},
11
+ {title: "User", url: "auth/user"},
12
+ ]
13
+ },
14
+ {title: "About", url: "/about"},
15
+ {title: "Greetings, Lord", url: "/greetings/Lord"},
16
+ {
17
+ title: "Test",
18
+ url: "#",
19
+ submenus: [
20
+ {title: "Sub 1", url: "/"},
21
+ {title: "Sub 2 long long title", url: "/about"}
22
+ ]
23
+ },
24
+ {title: "Sample url", url: "/sample"},
25
+ ]
@@ -0,0 +1,19 @@
1
+ export function setCookie(cookieName: string, cookieValue: string) {
2
+ document.cookie = cookieName + '=' + cookieValue + ';path=/';
3
+ }
4
+
5
+ export function unsetCookie(cookieName: string) {
6
+ document.cookie = cookieName + '=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/'
7
+ }
8
+
9
+ export function getCookie(cookieName: string): string {
10
+ let valuePrefix = cookieName + '=';
11
+ let cookieParts = document.cookie.split(';');
12
+ for(let partIndex = 0; partIndex < cookieParts.length; partIndex++) {
13
+ let cookiePart = cookieParts[partIndex].trim();
14
+ if (cookiePart.indexOf(valuePrefix) == 0) {
15
+ return cookiePart.substring(valuePrefix.length, cookiePart.length);
16
+ }
17
+ }
18
+ return '';
19
+ }
@@ -1,10 +1,13 @@
1
1
  <script lang="ts">
2
2
  import "../app.css";
3
- import Navigation from '$lib/components/Navigation.svelte';
4
- import navigationData from '$lib/data/navData.json';
5
- import logo from '$lib/assets/logo.png';
3
+ import Navigation from '$lib/components/navigation/Navigation.svelte';
4
+ import { navData } from '$lib/config/navData';
5
+ import { appBrand, appTitle } from '$lib/config/config';
6
+ import logo from '/static/logo.png';
6
7
  </script>
7
8
 
8
- <Navigation data={navigationData} logo={logo} brand="bearbrand"></Navigation>
9
-
10
- <slot></slot>
9
+ <title>{appTitle}</title>
10
+ <Navigation data={navData} logo={logo} brand={appBrand}></Navigation>
11
+ <div class="pl-10 pr-10">
12
+ <slot></slot>
13
+ </div>
@@ -1,6 +1,6 @@
1
1
  export function load({ params }) {
2
- return {
3
- title: 'hello ' + params.slug,
4
- content: 'hello ' + params.slug
5
- };
2
+ return {
3
+ title: 'Greetings, ' + params.slug,
4
+ content: 'Hello ' + params.slug
5
+ };
6
6
  }
@@ -1,9 +1,5 @@
1
- <h1>Greetings</h1>
2
-
3
- <h1>{data.title}</h1>
4
- <div>{@html data.content}</div>
5
-
6
-
7
1
  <script>
8
2
  export let data;
9
- </script>
3
+ </script>
4
+ <h1>{data.title}</h1>
5
+ <div>{@html data.content}</div>
@@ -0,0 +1,37 @@
1
+ <script lang="ts">
2
+ let data = [
3
+ {"id": "abc", "name": "Cy Ganderton", "job": "Quality Control Specialist", "favorite_color": "Blue"},
4
+ {"id": "def", "name": "Hart Hagerty", "job": "Desktop Support Tehcnician", "favorite_color": "Purple"},
5
+ {"id": "ghi", "name": "Brice Syre", "job": "Tax Accountant", "favorite_color": "Red"},
6
+ ]
7
+ </script>
8
+ <div class="overflow-x-auto">
9
+ <table class="table w-full">
10
+ <!-- head -->
11
+ <thead>
12
+ <tr>
13
+ <th></th>
14
+ <th>Name</th>
15
+ <th>Job</th>
16
+ <th>Favorite Color</th>
17
+ <th></th>
18
+ </tr>
19
+ </thead>
20
+ <tbody>
21
+ {#each data as row}
22
+ <tr>
23
+ <th>{row.id}</th>
24
+ <td>{row.name}</td>
25
+ <td>{row.job}</td>
26
+ <td>{row.favorite_color}</td>
27
+ <td>
28
+ <a class="btn" href="insert/{row.id}">Insert</a>
29
+ <a class="btn" href="update/{row.id}">Update</a>
30
+ <a class="btn btn-accent" href="delete/{row.id}">Delete</a>
31
+ </td>
32
+ </tr>
33
+ {/each}
34
+
35
+ </tbody>
36
+ </table>
37
+ </div>
@@ -4,6 +4,6 @@ export default {
4
4
  theme: {
5
5
  extend: {},
6
6
  },
7
- plugins: [],
7
+ plugins: [require("daisyui")],
8
8
  }
9
9
 
@@ -11,7 +11,7 @@ from module.auth.entity.group.api import (
11
11
  )
12
12
  from module.auth.entity.user.api import (
13
13
  register_api as register_user_api,
14
- register_login_api as register_user_login_api
14
+ register_auth_api as register_user_login_api
15
15
  )
16
16
 
17
17
 
@@ -5,5 +5,5 @@ authorizer: Authorizer = RPCAuthorizer(
5
5
  rpc_caller=rpc_caller,
6
6
  is_admin_rpc_name='auth_user_is_admin',
7
7
  is_guest_rpc_name='auth_user_is_guest',
8
- is_having_permission_rpc_name='auth_user_is_having_permission'
8
+ is_user_authorized_rpc_name='auth_is_user_authorized'
9
9
  )
@@ -6,6 +6,6 @@ from module.auth.component.user import guest_user
6
6
  token_scheme: TokenScheme = create_oauth2_bearer_token_scheme(
7
7
  guest_user=guest_user,
8
8
  token_util=token_util,
9
- token_url='/api/v1/login-oauth',
9
+ token_url='/api/v1/auth/login-oauth',
10
10
  token_cookie_key='auth_token'
11
11
  )
@@ -12,6 +12,6 @@ class Authorizer(ABC):
12
12
 
13
13
  @abstractmethod
14
14
  async def is_having_permission(
15
- self, user_id: str, permission_name
15
+ self, user_id: str, *permission_names: str
16
16
  ) -> bool:
17
17
  pass
@@ -9,12 +9,12 @@ class RPCAuthorizer(Authorizer):
9
9
  rpc_caller: Caller,
10
10
  is_admin_rpc_name: str,
11
11
  is_guest_rpc_name: str,
12
- is_having_permission_rpc_name: str,
12
+ is_user_authorized_rpc_name: str,
13
13
  ):
14
14
  self.rpc_caller = rpc_caller
15
15
  self.is_admin_rpc_name = is_admin_rpc_name
16
16
  self.is_guest_rpc_name = is_guest_rpc_name
17
- self.is_having_permission_rpc_name = is_having_permission_rpc_name
17
+ self.is_user_authorized_rpc_name = is_user_authorized_rpc_name
18
18
 
19
19
  async def is_admin(self, user_id: str) -> bool:
20
20
  return await self.rpc_caller.call(
@@ -27,8 +27,12 @@ class RPCAuthorizer(Authorizer):
27
27
  )
28
28
 
29
29
  async def is_having_permission(
30
- self, user_id: str, permission_name
30
+ self, user_id: str, *permission_names: str
31
31
  ) -> bool:
32
- return await self.rpc_caller.call(
33
- self.is_having_permission_rpc_name, user_id, permission_name
32
+ permission_map = await self.rpc_caller.call(
33
+ self.is_user_authorized_rpc_name, user_id, *permission_names
34
34
  )
35
+ for permission in permission_map:
36
+ if not permission_map[permission]:
37
+ return False
38
+ return True
@@ -12,7 +12,7 @@ def create_oauth2_bearer_token_scheme(
12
12
  guest_user: User,
13
13
  token_util: TokenUtil,
14
14
  token_url: str,
15
- token_cookie_key: str = 'auth_token'
15
+ token_cookie_key: str
16
16
  ) -> TokenScheme:
17
17
 
18
18
  oauth2_scheme = OAuth2PasswordBearer(
@@ -1,4 +1,4 @@
1
- from typing import Annotated
1
+ from typing import Annotated, List, Mapping
2
2
  from fastapi import FastAPI, Depends
3
3
  from fastapi.security import OAuth2PasswordRequestForm
4
4
  from logging import Logger
@@ -10,10 +10,11 @@ from module.auth.schema.user import (
10
10
  User, UserData, UserResult, UserLogin
11
11
  )
12
12
  from module.auth.schema.token import TokenData, TokenResponse
13
+ from module.auth.schema.request import RefreshTokenRequest, IsAuthorizedRequest
13
14
  from module.auth.component import token_scheme
14
15
 
15
16
 
16
- def register_login_api(
17
+ def register_auth_api(
17
18
  logger: Logger,
18
19
  app: FastAPI,
19
20
  authorizer: Authorizer,
@@ -22,7 +23,7 @@ def register_login_api(
22
23
  ):
23
24
  logger.info('🥪 Register Login API for "auth.user"')
24
25
 
25
- @app.post('/api/v1/login-oauth', response_model=TokenResponse)
26
+ @app.post('/api/v1/auth/login-oauth', response_model=TokenResponse)
26
27
  async def login_oauth(
27
28
  form_data: Annotated[OAuth2PasswordRequestForm, Depends()]
28
29
  ) -> TokenResponse:
@@ -30,21 +31,44 @@ def register_login_api(
30
31
  identity=form_data.username,
31
32
  password=form_data.password
32
33
  )
33
- return await _login(data=data)
34
+ return await _create_token(data=data)
34
35
 
35
- @app.post('/api/v1/login', response_model=TokenResponse)
36
+ @app.post('/api/v1/auth/login', response_model=TokenResponse)
36
37
  async def login(data: UserLogin) -> TokenResponse:
37
- return await _login(data=data)
38
+ return await _create_token(data=data)
38
39
 
39
- async def _login(data: UserLogin) -> TokenResponse:
40
+ async def _create_token(data: UserLogin) -> TokenResponse:
40
41
  try:
41
42
  token = await rpc_caller.call(
42
- 'auth_login', login_data=data.dict()
43
+ 'auth_create_token', login_data=data.dict()
43
44
  )
44
45
  return TokenResponse(access_token=token, token_type='bearer')
45
46
  except Exception as e:
46
47
  raise HTTPAPIException(error=e)
47
48
 
49
+ @app.post('/api/v1/auth/refresh-token', response_model=TokenResponse)
50
+ async def refresh_token(data: RefreshTokenRequest) -> TokenResponse:
51
+ try:
52
+ token = await rpc_caller.call(
53
+ 'auth_refresh_token', token=data.token
54
+ )
55
+ return TokenResponse(access_token=token, token_type='bearer')
56
+ except Exception as e:
57
+ raise HTTPAPIException(error=e)
58
+
59
+ @app.post('/api/v1/auth/is-authorized', response_model=Mapping[str, bool])
60
+ async def is_authorized(
61
+ data: IsAuthorizedRequest,
62
+ user_token_data: TokenData = Depends(token_scheme)
63
+ ) -> Mapping[str, str]:
64
+ try:
65
+ user_id = user_token_data.user_id
66
+ return await rpc_caller.call(
67
+ 'auth_is_user_authorized', id=user_id, *data.permission_names
68
+ )
69
+ except Exception as e:
70
+ raise HTTPAPIException(error=e)
71
+
48
72
 
49
73
  def register_api(
50
74
  logger: Logger,