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
@@ -1,4 +1,4 @@
1
- from typing import Optional
1
+ from typing import Optional, List, Mapping
2
2
  from core.model import RepoModel
3
3
  from module.auth.schema.user import (
4
4
  User, UserData, UserResult, UserLogin
@@ -33,10 +33,7 @@ class UserModel(
33
33
  self.admin_user_pasword = admin_user_password
34
34
 
35
35
  async def insert(self, data: UserData) -> User:
36
- if (
37
- self.admin_user is not None and
38
- data.username == self.admin_user.username
39
- ):
36
+ if self.admin_user is not None and self.is_admin(id):
40
37
  raise ValueError(
41
38
  'Invalid username: {data.username} is used by admin'
42
39
  )
@@ -48,7 +45,7 @@ class UserModel(
48
45
 
49
46
  async def update(self, id: str, data: UserData) -> User:
50
47
  if self.admin_user is not None:
51
- if id == self.admin_user.id:
48
+ if self.is_admin(id):
52
49
  raise ValueError(
53
50
  'Forbidden: editting admin user is not permitted'
54
51
  )
@@ -56,7 +53,7 @@ class UserModel(
56
53
  raise ValueError(
57
54
  'Invalid username: {data.username} is used by admin'
58
55
  )
59
- if id == self.guest_user.id:
56
+ if self.is_guest(id):
60
57
  raise ValueError(
61
58
  'Forbidden: editting guest user is not permitted'
62
59
  )
@@ -67,70 +64,65 @@ class UserModel(
67
64
  return await super().update(id, data)
68
65
 
69
66
  async def delete(self, id: str) -> User:
70
- if (
71
- self.admin_user is not None and
72
- id == self.admin_user.id
73
- ):
67
+ if self.admin_user is not None and self.is_admin(id):
74
68
  raise ValueError(
75
69
  'Forbidden: deleting admin user is not permitted'
76
70
  )
77
- if id == self.guest_user.id:
71
+ if self.is_guest(id):
78
72
  raise ValueError(
79
73
  'Forbidden: deleting guest user is not permitted'
80
74
  )
81
75
  return await super().delete(id)
82
76
 
83
- async def is_having_permission(
84
- self, id: str, permission_name: str
85
- ) -> bool:
86
- if await self.is_admin(id):
87
- return True
88
- if self.is_guest(id):
89
- return self._is_user_having_permission(
90
- self.guest_user, permission_name
91
- )
77
+ async def get_by_id(self, id: str) -> User:
78
+ if self.admin_user is not None and self.is_admin(id):
79
+ return self.admin_user
80
+ if id == self.guest_user.id:
81
+ return self.guest_user
82
+ return await super().get_by_id(id)
83
+
84
+ async def is_authorized(
85
+ self, id: str, *permission_names: str
86
+ ) -> Mapping[str, bool]:
92
87
  user = await self.get_by_id(id)
93
- return self._is_user_having_permission(user, permission_name)
88
+ if self.is_admin(user.id):
89
+ return {
90
+ permission_name: True for permission_name in permission_names
91
+ }
92
+ user_permission_names = self._get_permission_names(user)
93
+ return {
94
+ permission_name: permission_name in user_permission_names
95
+ for permission_name in permission_names
96
+ }
97
+
98
+ def _get_permission_names(self, user: User) -> List[str]:
99
+ permission_names = [
100
+ permission.name for permission in user.permissions
101
+ ]
102
+ for group in user.groups:
103
+ additional_permission_names = [
104
+ permission.name
105
+ for permission in group.permissions
106
+ if permission.name not in permission_names
107
+ ]
108
+ permission_names += additional_permission_names
109
+ return permission_names
94
110
 
95
- async def is_guest(self, id: str) -> bool:
111
+ def is_guest(self, id: str) -> bool:
96
112
  return id == self.guest_user.id
97
113
 
98
- async def is_admin(self, id: str) -> bool:
114
+ def is_admin(self, id: str) -> bool:
99
115
  if self.admin_user is None:
100
116
  return False
101
117
  return id == self.admin_user.id
102
118
 
103
- async def login(self, user_login: UserLogin) -> str:
104
- if user_login.identity == '':
105
- raise ValueError('Invalid identity: Identity is not provided')
106
- if (
107
- self.admin_user is not None
108
- and user_login.password == self.admin_user_pasword
109
- and (
110
- user_login.identity == self.admin_user.username or
111
- user_login.identity == self.admin_user.email or
112
- user_login.identity == self.admin_user.phone
113
- )
114
- ):
115
- return self._get_token(self.admin_user)
119
+ async def create_token(self, user_login: UserLogin) -> str:
116
120
  user = await self._get_user_by_user_login(user_login)
117
121
  return self._get_token(user)
118
122
 
119
- def _is_user_having_permission(
120
- self, user: User, permission_name: str
121
- ) -> bool:
122
- user_permission_names = [
123
- permission.name for permission in user.permissions
124
- ]
125
- if permission_name in user_permission_names:
126
- return True
127
- for group in user.groups:
128
- group_permission_names = [
129
- permission.name for permission in group.permissions
130
- ]
131
- if permission_name in group_permission_names:
132
- return True
133
- return False
123
+ async def refresh_token(self, auth_token_str: str) -> str:
124
+ user = await self._get_user_by_token(auth_token_str)
125
+ return self._get_token(user)
134
126
 
135
127
  def _get_token(self, user: User) -> str:
136
128
  token_data = TokenData(
@@ -141,4 +133,20 @@ class UserModel(
141
133
  return self.token_util.encode(token_data)
142
134
 
143
135
  async def _get_user_by_user_login(self, user_login: UserLogin) -> User:
136
+ if user_login.identity == '':
137
+ raise ValueError('Invalid identity: Identity is empty')
138
+ if (
139
+ self.admin_user is not None
140
+ and user_login.password == self.admin_user_pasword
141
+ and (
142
+ user_login.identity == self.admin_user.username or
143
+ user_login.identity == self.admin_user.email or
144
+ user_login.identity == self.admin_user.phone
145
+ )
146
+ ):
147
+ return self.admin_user
144
148
  return await self.repo.get_by_user_login(user_login)
149
+
150
+ async def _get_user_by_token(self, token: str) -> User:
151
+ token_data = self.token_util.decode(token)
152
+ return await self.get_by_id(token_data.user_id)
@@ -17,20 +17,35 @@ def register_rpc(
17
17
  logger.info('🥪 Register RPC handlers for "auth.user"')
18
18
 
19
19
  @rpc_server.register('auth_user_is_admin')
20
- async def is_admin(id: str) -> bool:
20
+ async def user_is_admin(id: str) -> bool:
21
+ '''
22
+ Used by RPC Authenticator
23
+ '''
21
24
  return await user_model.is_admin(id)
22
25
 
23
26
  @rpc_server.register('auth_user_is_guest')
24
- async def is_guest(id: str) -> bool:
27
+ async def user_is_guest(id: str) -> bool:
28
+ '''
29
+ Used by RPC Authenticator
30
+ '''
25
31
  return await user_model.is_guest(id)
26
32
 
27
- @rpc_server.register('auth_user_is_having_permission')
28
- async def is_having_permission(id: str, permission_name: str) -> bool:
29
- return await user_model.is_having_permission(id, permission_name)
33
+ @rpc_server.register('auth_is_user_authorized')
34
+ async def is_user_having_permission(
35
+ id: str, *permission_names: str
36
+ ) -> Mapping[str, bool]:
37
+ '''
38
+ Used by RPC Authenticator
39
+ '''
40
+ return await user_model.is_authorized(id, *permission_names)
30
41
 
31
- @rpc_server.register('auth_login')
32
- async def login(login_data: Mapping[str, str]) -> str:
33
- return await user_model.login(UserLogin(**login_data))
42
+ @rpc_server.register('auth_create_token')
43
+ async def create_token(login_data: Mapping[str, str]) -> str:
44
+ return await user_model.create_token(UserLogin(**login_data))
45
+
46
+ @rpc_server.register('auth_refresh_token')
47
+ async def refresh_token(token: str) -> str:
48
+ return await user_model.refresh_token(token)
34
49
 
35
50
  @rpc_server.register('auth_get_user')
36
51
  async def get(
@@ -0,0 +1,10 @@
1
+ from typing import List
2
+ from pydantic import BaseModel
3
+
4
+
5
+ class RefreshTokenRequest(BaseModel):
6
+ token: str
7
+
8
+
9
+ class IsAuthorizedRequest(BaseModel):
10
+ permission_names: List[str]
@@ -5,6 +5,10 @@ APP_PORT=httpPort
5
5
  APP_RELOAD=true
6
6
  APP_MAX_NOT_READY=10
7
7
 
8
+ PUBLIC_BRAND=PascalAppName
9
+ PUBLIC_TITLE=PascalAppName
10
+ PUBLIC_AUTH_TOKEN_COOKIE_KEY=auth_token
11
+
8
12
  APP_AUTH_TOKEN_EXPIRE_SECONDS=300
9
13
  APP_AUTH_TOKEN_TYPE=jwt
10
14
  APP_AUTH_JWT_TOKEN_SECRET_KEY=Alch3mist
@@ -32,7 +32,7 @@ async def test_insert_group_and_get_success(
32
32
  async for client in test_client_generator:
33
33
  # login
34
34
  login_admin_response = await client.post(
35
- '/api/v1/login',
35
+ '/api/v1/auth/login',
36
36
  json={
37
37
  'identity': app_auth_admin_username,
38
38
  'password': app_auth_admin_password
@@ -94,7 +94,7 @@ async def test_update_group_and_get_success(
94
94
  async for client in test_client_generator:
95
95
  # login
96
96
  login_admin_response = await client.post(
97
- '/api/v1/login',
97
+ '/api/v1/auth/login',
98
98
  json={
99
99
  'identity': app_auth_admin_username,
100
100
  'password': app_auth_admin_password,
@@ -172,7 +172,7 @@ async def test_delete_group_and_get_success(
172
172
  async for client in test_client_generator:
173
173
  # login
174
174
  login_admin_response = await client.post(
175
- '/api/v1/login',
175
+ '/api/v1/auth/login',
176
176
  json={
177
177
  'identity': app_auth_admin_username,
178
178
  'password': app_auth_admin_password
@@ -28,7 +28,7 @@ async def test_insert_permission_and_get_success(
28
28
  async for client in test_client_generator:
29
29
  # login
30
30
  login_admin_response = await client.post(
31
- '/api/v1/login',
31
+ '/api/v1/auth/login',
32
32
  json={
33
33
  'identity': app_auth_admin_username,
34
34
  'password': app_auth_admin_password
@@ -90,7 +90,7 @@ async def test_update_permission_and_get_success(
90
90
  async for client in test_client_generator:
91
91
  # login
92
92
  login_admin_response = await client.post(
93
- '/api/v1/login',
93
+ '/api/v1/auth/login',
94
94
  json={
95
95
  'identity': app_auth_admin_username,
96
96
  'password': app_auth_admin_password,
@@ -169,7 +169,7 @@ async def test_delete_permission_and_get_success(
169
169
  async for client in test_client_generator:
170
170
  # login
171
171
  login_admin_response = await client.post(
172
- '/api/v1/login',
172
+ '/api/v1/auth/login',
173
173
  json={
174
174
  'identity': app_auth_admin_username,
175
175
  'password': app_auth_admin_password
@@ -48,7 +48,7 @@ async def test_insert_user_and_get_success(
48
48
  async for client in test_client_generator:
49
49
  # login
50
50
  login_admin_response = await client.post(
51
- '/api/v1/login',
51
+ '/api/v1/auth/login',
52
52
  json={
53
53
  'identity': app_auth_admin_username,
54
54
  'password': app_auth_admin_password
@@ -110,7 +110,7 @@ async def test_update_user_and_get_success(
110
110
  async for client in test_client_generator:
111
111
  # login
112
112
  login_admin_response = await client.post(
113
- '/api/v1/login',
113
+ '/api/v1/auth/login',
114
114
  json={
115
115
  'identity': app_auth_admin_username,
116
116
  'password': app_auth_admin_password,
@@ -188,7 +188,7 @@ async def test_delete_user_and_get_success(
188
188
  async for client in test_client_generator:
189
189
  # login
190
190
  login_admin_response = await client.post(
191
- '/api/v1/login',
191
+ '/api/v1/auth/login',
192
192
  json={
193
193
  'identity': app_auth_admin_username,
194
194
  'password': app_auth_admin_password
@@ -10,7 +10,7 @@ async def test_admin_user_login_success(
10
10
  ):
11
11
  async for client in test_client_generator:
12
12
  login_response = await client.post(
13
- '/api/v1/login',
13
+ '/api/v1/auth/login',
14
14
  json={
15
15
  'identity': app_auth_admin_username,
16
16
  'password': app_auth_admin_password
@@ -28,7 +28,7 @@ async def test_admin_user_login_empty_identity_failed(
28
28
  ):
29
29
  async for client in test_client_generator:
30
30
  login_response = await client.post(
31
- '/api/v1/login',
31
+ '/api/v1/auth/login',
32
32
  json={
33
33
  'identity': '',
34
34
  'password': app_auth_admin_password
@@ -43,7 +43,7 @@ async def test_admin_user_login_invalid_identity_failed(
43
43
  ):
44
44
  async for client in test_client_generator:
45
45
  login_response = await client.post(
46
- '/api/v1/login',
46
+ '/api/v1/auth/login',
47
47
  json={
48
48
  'identity': 'invalid-identity',
49
49
  'password': app_auth_admin_password
@@ -58,7 +58,7 @@ async def test_admin_user_failed_invalid_password(
58
58
  ):
59
59
  async for client in test_client_generator:
60
60
  login_response = await client.post(
61
- '/api/v1/login',
61
+ '/api/v1/auth/login',
62
62
  json={
63
63
  'identity': app_auth_admin_username,
64
64
  'password': 'invalid-password'
@@ -74,7 +74,7 @@ async def test_create_normal_user_and_login_with_username_success(
74
74
  async for client in test_client_generator:
75
75
  # login
76
76
  login_admin_response = await client.post(
77
- '/api/v1/login',
77
+ '/api/v1/auth/login',
78
78
  json={
79
79
  'identity': app_auth_admin_username,
80
80
  'password': app_auth_admin_password
@@ -104,7 +104,7 @@ async def test_create_normal_user_and_login_with_username_success(
104
104
  assert create_response.status_code == 200
105
105
  # login
106
106
  login_admin_response = await client.post(
107
- '/api/v1/login',
107
+ '/api/v1/auth/login',
108
108
  json={
109
109
  'identity': 'test-login-user-with-username-success',
110
110
  'password': 'test-password'
@@ -123,7 +123,7 @@ async def test_create_normal_user_and_login_with_phone_success(
123
123
  async for client in test_client_generator:
124
124
  # login
125
125
  login_admin_response = await client.post(
126
- '/api/v1/login',
126
+ '/api/v1/auth/login',
127
127
  json={
128
128
  'identity': app_auth_admin_username,
129
129
  'password': app_auth_admin_password
@@ -153,7 +153,7 @@ async def test_create_normal_user_and_login_with_phone_success(
153
153
  assert create_response.status_code == 200
154
154
  # login
155
155
  login_admin_response = await client.post(
156
- '/api/v1/login',
156
+ '/api/v1/auth/login',
157
157
  json={
158
158
  'identity': '+628123456789',
159
159
  'password': 'test-password'
@@ -172,7 +172,7 @@ async def test_create_normal_user_and_login_with_email_success(
172
172
  async for client in test_client_generator:
173
173
  # login
174
174
  login_admin_response = await client.post(
175
- '/api/v1/login',
175
+ '/api/v1/auth/login',
176
176
  json={
177
177
  'identity': app_auth_admin_username,
178
178
  'password': app_auth_admin_password
@@ -202,7 +202,7 @@ async def test_create_normal_user_and_login_with_email_success(
202
202
  assert create_response.status_code == 200
203
203
  # login
204
204
  login_admin_response = await client.post(
205
- '/api/v1/login',
205
+ '/api/v1/auth/login',
206
206
  json={
207
207
  'identity': 'test-login-user-with-email-success@test.com',
208
208
  'password': 'test-password'
@@ -221,7 +221,7 @@ async def test_create_normal_user_and_login_failed(
221
221
  async for client in test_client_generator:
222
222
  # login
223
223
  login_admin_response = await client.post(
224
- '/api/v1/login',
224
+ '/api/v1/auth/login',
225
225
  json={
226
226
  'identity': app_auth_admin_username,
227
227
  'password': app_auth_admin_password
@@ -251,7 +251,7 @@ async def test_create_normal_user_and_login_failed(
251
251
  assert create_response.status_code == 200
252
252
  # login
253
253
  login_admin_response = await client.post(
254
- '/api/v1/login',
254
+ '/api/v1/auth/login',
255
255
  json={
256
256
  'identity': 'test-login-user-with-email-failed',
257
257
  'password': 'invalid-password'
@@ -2,6 +2,7 @@ from typing import Any
2
2
  from ..._group import project_add_group
3
3
  from ....task.task import Task
4
4
  from ....task.decorator import python_task
5
+ from ....task.cmd_task import CmdTask
5
6
  from ....task.resource_maker import ResourceMaker
6
7
  from ....runner import runner
7
8
  from .._common.input import (
@@ -18,6 +19,7 @@ import asyncio
18
19
  import os
19
20
 
20
21
  current_dir = os.path.dirname(__file__)
22
+ codemod_dir = os.path.join(current_dir, 'nodejs', 'codemod')
21
23
 
22
24
 
23
25
  @python_task(
@@ -79,8 +81,7 @@ copy_resource = ResourceMaker(
79
81
 
80
82
 
81
83
  @python_task(
82
- name='fastapp-crud',
83
- group=project_add_group,
84
+ name='register-crud',
84
85
  inputs=[
85
86
  project_dir_input,
86
87
  app_name_input,
@@ -91,10 +92,9 @@ copy_resource = ResourceMaker(
91
92
  ],
92
93
  upstreams=[
93
94
  copy_resource,
94
- ],
95
- runner=runner
95
+ ]
96
96
  )
97
- async def add_fastapp_crud(*args: Any, **kwargs: Any):
97
+ async def register_crud(*args: Any, **kwargs: Any):
98
98
  task: Task = kwargs.get('_task')
99
99
  project_dir = kwargs.get('project_dir', '.')
100
100
  app_name = kwargs.get('app_name')
@@ -112,7 +112,56 @@ async def add_fastapp_crud(*args: Any, **kwargs: Any):
112
112
  task, project_dir, kebab_app_name, snake_module_name,
113
113
  snake_entity_name
114
114
  )),
115
+ asyncio.create_task(register_permission(
116
+ task, project_dir, kebab_app_name, snake_module_name,
117
+ snake_entity_name
118
+ )),
115
119
  )
120
+
121
+
122
+ prepare_codemod = CmdTask(
123
+ name='prepare-codemod',
124
+ cwd=codemod_dir,
125
+ cmd=[
126
+ 'npm install --save-dev',
127
+ 'node_modules/.bin/tsc'
128
+ ]
129
+ )
130
+
131
+
132
+ nav_file_path = '{{input.project_dir}}/src/{{util.to_kebab_case(input.app_name)}}/src/frontend/src/lib/config/navData.ts' # noqa
133
+ var_name = 'navData'
134
+ title = '{{util.to_pascal_case(input.entity_name)}}'
135
+ url = '{{util.to_kebab_case(input.module_name)}}/{{util.to_kebab_case(input.entity_name)}}' # noqa
136
+ permission = ''
137
+ add_navigation = CmdTask(
138
+ name='add-navigation',
139
+ inputs=[
140
+ project_dir_input,
141
+ app_name_input,
142
+ module_name_input,
143
+ entity_name_input,
144
+ ],
145
+ upstreams=[
146
+ copy_resource,
147
+ prepare_codemod,
148
+ ],
149
+ retry=0,
150
+ cmd=f'node {codemod_dir}/dist/addNav.js "{nav_file_path}" "{var_name}" "{title}" "{url}" "{permission}"' # noqa
151
+ )
152
+
153
+
154
+ @python_task(
155
+ name='fastapp-crud',
156
+ group=project_add_group,
157
+ upstreams=[
158
+ register_crud,
159
+ add_navigation
160
+ ],
161
+ runner=runner
162
+ )
163
+ async def add_fastapp_crud(*args: Any, **kwargs: Any):
164
+ task: Task = kwargs.get('_task')
116
165
  task.print_out('Success')
117
166
 
118
167
 
@@ -188,3 +237,35 @@ async def register_rpc(
188
237
  )
189
238
  task.print_out(f'Write modified code to: {module_rpc_file_path}')
190
239
  await write_text_file_async(module_rpc_file_path, code)
240
+
241
+
242
+ async def register_permission(
243
+ task: Task,
244
+ project_dir: str,
245
+ kebab_app_name: str,
246
+ snake_module_name: str,
247
+ snake_entity_name: str
248
+ ):
249
+ module_register_permission_file_path = os.path.join(
250
+ project_dir, 'src', kebab_app_name, 'src', 'module', 'auth',
251
+ 'register_permission.py'
252
+ )
253
+ task.print_out(f'Read code from: {module_register_permission_file_path}')
254
+ code = await read_text_file_async(module_register_permission_file_path)
255
+ code = append_code_to_function(
256
+ code=code,
257
+ function_name='register_permission',
258
+ new_code='\n'.join([
259
+ 'await ensure_entity_permission(',
260
+ f" module_name='{snake_module_name}', entity_name='{snake_entity_name}'", # noqa
261
+ ')'
262
+ ])
263
+ )
264
+ task.print_out(
265
+ f'Add "ensure_entity_permission" call for {snake_entity_name} ' +
266
+ 'to the code'
267
+ )
268
+ task.print_out(
269
+ f'Write modified code to: {module_register_permission_file_path}'
270
+ )
271
+ await write_text_file_async(module_register_permission_file_path, code)
@@ -0,0 +1 @@
1
+ node_modules