geek-cafe-saas-sdk 0.6.0__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.

Potentially problematic release.


This version of geek-cafe-saas-sdk might be problematic. Click here for more details.

Files changed (194) hide show
  1. geek_cafe_saas_sdk/__init__.py +9 -0
  2. geek_cafe_saas_sdk/core/__init__.py +11 -0
  3. geek_cafe_saas_sdk/core/audit_mixin.py +33 -0
  4. geek_cafe_saas_sdk/core/error_codes.py +132 -0
  5. geek_cafe_saas_sdk/core/service_errors.py +19 -0
  6. geek_cafe_saas_sdk/core/service_result.py +121 -0
  7. geek_cafe_saas_sdk/decorators/__init__.py +64 -0
  8. geek_cafe_saas_sdk/decorators/auth.py +373 -0
  9. geek_cafe_saas_sdk/decorators/core.py +358 -0
  10. geek_cafe_saas_sdk/domains/__init__.py +0 -0
  11. geek_cafe_saas_sdk/domains/analytics/__init__.py +0 -0
  12. geek_cafe_saas_sdk/domains/analytics/handlers/__init__.py +0 -0
  13. geek_cafe_saas_sdk/domains/analytics/models/__init__.py +9 -0
  14. geek_cafe_saas_sdk/domains/analytics/models/website_analytics.py +219 -0
  15. geek_cafe_saas_sdk/domains/analytics/models/website_analytics_summary.py +220 -0
  16. geek_cafe_saas_sdk/domains/analytics/services/__init__.py +11 -0
  17. geek_cafe_saas_sdk/domains/analytics/services/website_analytics_service.py +232 -0
  18. geek_cafe_saas_sdk/domains/analytics/services/website_analytics_summary_service.py +212 -0
  19. geek_cafe_saas_sdk/domains/analytics/services/website_analytics_tally_service.py +610 -0
  20. geek_cafe_saas_sdk/domains/auth/__init__.py +0 -0
  21. geek_cafe_saas_sdk/domains/auth/handlers/__init__.py +0 -0
  22. geek_cafe_saas_sdk/domains/auth/handlers/users/create/app.py +41 -0
  23. geek_cafe_saas_sdk/domains/auth/handlers/users/delete/app.py +41 -0
  24. geek_cafe_saas_sdk/domains/auth/handlers/users/get/app.py +39 -0
  25. geek_cafe_saas_sdk/domains/auth/handlers/users/list/app.py +36 -0
  26. geek_cafe_saas_sdk/domains/auth/handlers/users/update/app.py +44 -0
  27. geek_cafe_saas_sdk/domains/auth/models/__init__.py +13 -0
  28. geek_cafe_saas_sdk/domains/auth/models/permission.py +134 -0
  29. geek_cafe_saas_sdk/domains/auth/models/resource_permission.py +245 -0
  30. geek_cafe_saas_sdk/domains/auth/models/role.py +213 -0
  31. geek_cafe_saas_sdk/domains/auth/models/user.py +285 -0
  32. geek_cafe_saas_sdk/domains/auth/services/__init__.py +16 -0
  33. geek_cafe_saas_sdk/domains/auth/services/authorization_service.py +376 -0
  34. geek_cafe_saas_sdk/domains/auth/services/permission_registry.py +464 -0
  35. geek_cafe_saas_sdk/domains/auth/services/resource_permission_service.py +408 -0
  36. geek_cafe_saas_sdk/domains/auth/services/user_service.py +274 -0
  37. geek_cafe_saas_sdk/domains/communities/__init__.py +0 -0
  38. geek_cafe_saas_sdk/domains/communities/handlers/__init__.py +0 -0
  39. geek_cafe_saas_sdk/domains/communities/handlers/communities/create/app.py +41 -0
  40. geek_cafe_saas_sdk/domains/communities/handlers/communities/delete/app.py +41 -0
  41. geek_cafe_saas_sdk/domains/communities/handlers/communities/get/app.py +39 -0
  42. geek_cafe_saas_sdk/domains/communities/handlers/communities/list/app.py +36 -0
  43. geek_cafe_saas_sdk/domains/communities/handlers/communities/update/app.py +44 -0
  44. geek_cafe_saas_sdk/domains/communities/models/__init__.py +6 -0
  45. geek_cafe_saas_sdk/domains/communities/models/community.py +326 -0
  46. geek_cafe_saas_sdk/domains/communities/models/community_member.py +227 -0
  47. geek_cafe_saas_sdk/domains/communities/services/__init__.py +6 -0
  48. geek_cafe_saas_sdk/domains/communities/services/community_member_service.py +412 -0
  49. geek_cafe_saas_sdk/domains/communities/services/community_service.py +479 -0
  50. geek_cafe_saas_sdk/domains/events/__init__.py +0 -0
  51. geek_cafe_saas_sdk/domains/events/handlers/__init__.py +0 -0
  52. geek_cafe_saas_sdk/domains/events/handlers/attendees/app.py +67 -0
  53. geek_cafe_saas_sdk/domains/events/handlers/cancel/app.py +66 -0
  54. geek_cafe_saas_sdk/domains/events/handlers/check_in/app.py +60 -0
  55. geek_cafe_saas_sdk/domains/events/handlers/create/app.py +93 -0
  56. geek_cafe_saas_sdk/domains/events/handlers/delete/app.py +42 -0
  57. geek_cafe_saas_sdk/domains/events/handlers/get/app.py +39 -0
  58. geek_cafe_saas_sdk/domains/events/handlers/invite/app.py +98 -0
  59. geek_cafe_saas_sdk/domains/events/handlers/list/app.py +125 -0
  60. geek_cafe_saas_sdk/domains/events/handlers/publish/app.py +49 -0
  61. geek_cafe_saas_sdk/domains/events/handlers/rsvp/app.py +83 -0
  62. geek_cafe_saas_sdk/domains/events/handlers/update/app.py +44 -0
  63. geek_cafe_saas_sdk/domains/events/models/__init__.py +3 -0
  64. geek_cafe_saas_sdk/domains/events/models/event.py +681 -0
  65. geek_cafe_saas_sdk/domains/events/models/event_attendee.py +324 -0
  66. geek_cafe_saas_sdk/domains/events/services/__init__.py +9 -0
  67. geek_cafe_saas_sdk/domains/events/services/event_attendee_service.py +571 -0
  68. geek_cafe_saas_sdk/domains/events/services/event_service.py +684 -0
  69. geek_cafe_saas_sdk/domains/files/__init__.py +0 -0
  70. geek_cafe_saas_sdk/domains/files/models/__init__.py +0 -0
  71. geek_cafe_saas_sdk/domains/files/models/directory.py +258 -0
  72. geek_cafe_saas_sdk/domains/files/models/file.py +312 -0
  73. geek_cafe_saas_sdk/domains/files/models/file_share.py +268 -0
  74. geek_cafe_saas_sdk/domains/files/models/file_version.py +216 -0
  75. geek_cafe_saas_sdk/domains/files/services/__init__.py +0 -0
  76. geek_cafe_saas_sdk/domains/files/services/directory_service.py +701 -0
  77. geek_cafe_saas_sdk/domains/files/services/file_share_service.py +663 -0
  78. geek_cafe_saas_sdk/domains/files/services/file_system_service.py +575 -0
  79. geek_cafe_saas_sdk/domains/files/services/file_version_service.py +739 -0
  80. geek_cafe_saas_sdk/domains/files/services/s3_file_service.py +501 -0
  81. geek_cafe_saas_sdk/domains/messaging/__init__.py +0 -0
  82. geek_cafe_saas_sdk/domains/messaging/handlers/__init__.py +0 -0
  83. geek_cafe_saas_sdk/domains/messaging/handlers/chat_channels/create/app.py +86 -0
  84. geek_cafe_saas_sdk/domains/messaging/handlers/chat_channels/delete/app.py +65 -0
  85. geek_cafe_saas_sdk/domains/messaging/handlers/chat_channels/get/app.py +64 -0
  86. geek_cafe_saas_sdk/domains/messaging/handlers/chat_channels/list/app.py +97 -0
  87. geek_cafe_saas_sdk/domains/messaging/handlers/chat_channels/update/app.py +149 -0
  88. geek_cafe_saas_sdk/domains/messaging/handlers/chat_messages/create/app.py +67 -0
  89. geek_cafe_saas_sdk/domains/messaging/handlers/chat_messages/delete/app.py +65 -0
  90. geek_cafe_saas_sdk/domains/messaging/handlers/chat_messages/get/app.py +64 -0
  91. geek_cafe_saas_sdk/domains/messaging/handlers/chat_messages/list/app.py +102 -0
  92. geek_cafe_saas_sdk/domains/messaging/handlers/chat_messages/update/app.py +127 -0
  93. geek_cafe_saas_sdk/domains/messaging/handlers/contact_threads/create/app.py +94 -0
  94. geek_cafe_saas_sdk/domains/messaging/handlers/contact_threads/delete/app.py +66 -0
  95. geek_cafe_saas_sdk/domains/messaging/handlers/contact_threads/get/app.py +67 -0
  96. geek_cafe_saas_sdk/domains/messaging/handlers/contact_threads/list/app.py +95 -0
  97. geek_cafe_saas_sdk/domains/messaging/handlers/contact_threads/update/app.py +156 -0
  98. geek_cafe_saas_sdk/domains/messaging/models/__init__.py +13 -0
  99. geek_cafe_saas_sdk/domains/messaging/models/chat_channel.py +337 -0
  100. geek_cafe_saas_sdk/domains/messaging/models/chat_channel_member.py +180 -0
  101. geek_cafe_saas_sdk/domains/messaging/models/chat_message.py +426 -0
  102. geek_cafe_saas_sdk/domains/messaging/models/contact_thread.py +392 -0
  103. geek_cafe_saas_sdk/domains/messaging/services/__init__.py +11 -0
  104. geek_cafe_saas_sdk/domains/messaging/services/chat_channel_service.py +700 -0
  105. geek_cafe_saas_sdk/domains/messaging/services/chat_message_service.py +491 -0
  106. geek_cafe_saas_sdk/domains/messaging/services/contact_thread_service.py +497 -0
  107. geek_cafe_saas_sdk/domains/tenancy/__init__.py +0 -0
  108. geek_cafe_saas_sdk/domains/tenancy/handlers/__init__.py +0 -0
  109. geek_cafe_saas_sdk/domains/tenancy/handlers/subscriptions/activate/app.py +52 -0
  110. geek_cafe_saas_sdk/domains/tenancy/handlers/subscriptions/active/app.py +37 -0
  111. geek_cafe_saas_sdk/domains/tenancy/handlers/subscriptions/cancel/app.py +55 -0
  112. geek_cafe_saas_sdk/domains/tenancy/handlers/subscriptions/get/app.py +39 -0
  113. geek_cafe_saas_sdk/domains/tenancy/handlers/subscriptions/list/app.py +44 -0
  114. geek_cafe_saas_sdk/domains/tenancy/handlers/subscriptions/record_payment/app.py +56 -0
  115. geek_cafe_saas_sdk/domains/tenancy/handlers/tenants/get/app.py +39 -0
  116. geek_cafe_saas_sdk/domains/tenancy/handlers/tenants/me/app.py +37 -0
  117. geek_cafe_saas_sdk/domains/tenancy/handlers/tenants/signup/app.py +61 -0
  118. geek_cafe_saas_sdk/domains/tenancy/handlers/tenants/update/app.py +44 -0
  119. geek_cafe_saas_sdk/domains/tenancy/models/__init__.py +6 -0
  120. geek_cafe_saas_sdk/domains/tenancy/models/subscription.py +440 -0
  121. geek_cafe_saas_sdk/domains/tenancy/models/tenant.py +258 -0
  122. geek_cafe_saas_sdk/domains/tenancy/services/__init__.py +6 -0
  123. geek_cafe_saas_sdk/domains/tenancy/services/subscription_service.py +557 -0
  124. geek_cafe_saas_sdk/domains/tenancy/services/tenant_service.py +575 -0
  125. geek_cafe_saas_sdk/domains/voting/__init__.py +0 -0
  126. geek_cafe_saas_sdk/domains/voting/handlers/__init__.py +0 -0
  127. geek_cafe_saas_sdk/domains/voting/handlers/votes/create/app.py +128 -0
  128. geek_cafe_saas_sdk/domains/voting/handlers/votes/delete/app.py +41 -0
  129. geek_cafe_saas_sdk/domains/voting/handlers/votes/get/app.py +39 -0
  130. geek_cafe_saas_sdk/domains/voting/handlers/votes/list/app.py +38 -0
  131. geek_cafe_saas_sdk/domains/voting/handlers/votes/summerize/README.md +3 -0
  132. geek_cafe_saas_sdk/domains/voting/handlers/votes/update/app.py +44 -0
  133. geek_cafe_saas_sdk/domains/voting/models/__init__.py +9 -0
  134. geek_cafe_saas_sdk/domains/voting/models/vote.py +231 -0
  135. geek_cafe_saas_sdk/domains/voting/models/vote_summary.py +193 -0
  136. geek_cafe_saas_sdk/domains/voting/services/__init__.py +11 -0
  137. geek_cafe_saas_sdk/domains/voting/services/vote_service.py +264 -0
  138. geek_cafe_saas_sdk/domains/voting/services/vote_summary_service.py +198 -0
  139. geek_cafe_saas_sdk/domains/voting/services/vote_tally_service.py +533 -0
  140. geek_cafe_saas_sdk/lambda_handlers/README.md +404 -0
  141. geek_cafe_saas_sdk/lambda_handlers/__init__.py +67 -0
  142. geek_cafe_saas_sdk/lambda_handlers/_base/__init__.py +25 -0
  143. geek_cafe_saas_sdk/lambda_handlers/_base/api_key_handler.py +129 -0
  144. geek_cafe_saas_sdk/lambda_handlers/_base/authorized_secure_handler.py +218 -0
  145. geek_cafe_saas_sdk/lambda_handlers/_base/base_handler.py +185 -0
  146. geek_cafe_saas_sdk/lambda_handlers/_base/handler_factory.py +256 -0
  147. geek_cafe_saas_sdk/lambda_handlers/_base/public_handler.py +53 -0
  148. geek_cafe_saas_sdk/lambda_handlers/_base/secure_handler.py +89 -0
  149. geek_cafe_saas_sdk/lambda_handlers/_base/service_pool.py +94 -0
  150. geek_cafe_saas_sdk/lambda_handlers/directories/create/app.py +79 -0
  151. geek_cafe_saas_sdk/lambda_handlers/directories/delete/app.py +76 -0
  152. geek_cafe_saas_sdk/lambda_handlers/directories/get/app.py +74 -0
  153. geek_cafe_saas_sdk/lambda_handlers/directories/list/app.py +75 -0
  154. geek_cafe_saas_sdk/lambda_handlers/directories/move/app.py +79 -0
  155. geek_cafe_saas_sdk/lambda_handlers/files/delete/app.py +121 -0
  156. geek_cafe_saas_sdk/lambda_handlers/files/download/app.py +187 -0
  157. geek_cafe_saas_sdk/lambda_handlers/files/get/app.py +127 -0
  158. geek_cafe_saas_sdk/lambda_handlers/files/list/app.py +108 -0
  159. geek_cafe_saas_sdk/lambda_handlers/files/share/app.py +83 -0
  160. geek_cafe_saas_sdk/lambda_handlers/files/shares/list/app.py +84 -0
  161. geek_cafe_saas_sdk/lambda_handlers/files/shares/revoke/app.py +76 -0
  162. geek_cafe_saas_sdk/lambda_handlers/files/update/app.py +143 -0
  163. geek_cafe_saas_sdk/lambda_handlers/files/upload/app.py +151 -0
  164. geek_cafe_saas_sdk/middleware/__init__.py +36 -0
  165. geek_cafe_saas_sdk/middleware/auth.py +85 -0
  166. geek_cafe_saas_sdk/middleware/authorization.py +523 -0
  167. geek_cafe_saas_sdk/middleware/cors.py +63 -0
  168. geek_cafe_saas_sdk/middleware/error_handling.py +114 -0
  169. geek_cafe_saas_sdk/middleware/validation.py +80 -0
  170. geek_cafe_saas_sdk/models/__init__.py +20 -0
  171. geek_cafe_saas_sdk/models/base_model.py +233 -0
  172. geek_cafe_saas_sdk/services/__init__.py +18 -0
  173. geek_cafe_saas_sdk/services/database_service.py +441 -0
  174. geek_cafe_saas_sdk/utilities/__init__.py +88 -0
  175. geek_cafe_saas_sdk/utilities/cognito_utility.py +568 -0
  176. geek_cafe_saas_sdk/utilities/custom_exceptions.py +183 -0
  177. geek_cafe_saas_sdk/utilities/datetime_utility.py +410 -0
  178. geek_cafe_saas_sdk/utilities/dictionary_utility.py +78 -0
  179. geek_cafe_saas_sdk/utilities/dynamodb_utils.py +151 -0
  180. geek_cafe_saas_sdk/utilities/environment_loader.py +149 -0
  181. geek_cafe_saas_sdk/utilities/environment_variables.py +228 -0
  182. geek_cafe_saas_sdk/utilities/http_body_parameters.py +44 -0
  183. geek_cafe_saas_sdk/utilities/http_path_parameters.py +60 -0
  184. geek_cafe_saas_sdk/utilities/http_status_code.py +63 -0
  185. geek_cafe_saas_sdk/utilities/jwt_utility.py +234 -0
  186. geek_cafe_saas_sdk/utilities/lambda_event_utility.py +776 -0
  187. geek_cafe_saas_sdk/utilities/logging_utility.py +64 -0
  188. geek_cafe_saas_sdk/utilities/message_query_helper.py +340 -0
  189. geek_cafe_saas_sdk/utilities/response.py +209 -0
  190. geek_cafe_saas_sdk/utilities/string_functions.py +180 -0
  191. geek_cafe_saas_sdk-0.6.0.dist-info/METADATA +397 -0
  192. geek_cafe_saas_sdk-0.6.0.dist-info/RECORD +194 -0
  193. geek_cafe_saas_sdk-0.6.0.dist-info/WHEEL +4 -0
  194. geek_cafe_saas_sdk-0.6.0.dist-info/licenses/LICENSE +47 -0
@@ -0,0 +1,464 @@
1
+ """
2
+ Copyright 2024-2025 Geek Cafe, LLC
3
+ MIT License. See Project Root for the license information.
4
+
5
+ Permission Registry for extensible permission definitions.
6
+ Allows applications to register custom permissions and roles.
7
+ """
8
+
9
+ from typing import Dict, List, Optional, Set
10
+ from dataclasses import dataclass
11
+ import threading
12
+
13
+
14
+ @dataclass
15
+ class PermissionDefinition:
16
+ """Definition of a permission."""
17
+ code: str # "events:read"
18
+ name: str # "Read Events"
19
+ description: str
20
+ category: str # "events"
21
+ is_system: bool = True
22
+
23
+
24
+ @dataclass
25
+ class RoleDefinition:
26
+ """Definition of a role."""
27
+ code: str # "tenant_admin"
28
+ name: str # "Tenant Administrator"
29
+ description: str
30
+ permissions: List[str] # Permission codes
31
+ scope: str = "tenant" # "global" or "tenant"
32
+ inherits_from: List[str] = None # Role codes
33
+ level: int = 0
34
+ is_system: bool = True
35
+ is_assignable: bool = True
36
+
37
+ def __post_init__(self):
38
+ if self.inherits_from is None:
39
+ self.inherits_from = []
40
+
41
+
42
+ class PermissionRegistry:
43
+ """
44
+ Singleton registry for permissions and roles.
45
+
46
+ Allows applications to register custom permissions and roles
47
+ that extend the base system. Provides in-memory lookup for
48
+ fast permission resolution.
49
+
50
+ Thread-safe for concurrent access.
51
+ """
52
+
53
+ _instance = None
54
+ _lock = threading.Lock()
55
+
56
+ def __new__(cls):
57
+ if cls._instance is None:
58
+ with cls._lock:
59
+ if cls._instance is None:
60
+ cls._instance = super().__new__(cls)
61
+ cls._instance._initialized = False
62
+ return cls._instance
63
+
64
+ def __init__(self):
65
+ if self._initialized:
66
+ return
67
+
68
+ self._permissions: Dict[str, PermissionDefinition] = {}
69
+ self._roles: Dict[str, RoleDefinition] = {}
70
+ self._categories: Set[str] = set()
71
+ self._lock = threading.Lock()
72
+
73
+ # Register default permissions and roles
74
+ self._register_defaults()
75
+ self._initialized = True
76
+
77
+ def _register_defaults(self):
78
+ """Register default system permissions and roles."""
79
+
80
+ # Platform Permissions
81
+ self.register_permission(PermissionDefinition(
82
+ code="platform:admin",
83
+ name="Platform Admin",
84
+ description="Full system access across all tenants",
85
+ category="platform",
86
+ is_system=True
87
+ ))
88
+
89
+ self.register_permission(PermissionDefinition(
90
+ code="platform:support",
91
+ name="Platform Support",
92
+ description="Read-only access across tenants for support",
93
+ category="platform",
94
+ is_system=True
95
+ ))
96
+
97
+ # Tenant Permissions
98
+ self.register_permission(PermissionDefinition(
99
+ code="tenant:admin",
100
+ name="Tenant Admin",
101
+ description="Full administrative access within tenant",
102
+ category="tenant",
103
+ is_system=True
104
+ ))
105
+
106
+ self.register_permission(PermissionDefinition(
107
+ code="tenant:read",
108
+ name="Read Tenant",
109
+ description="View tenant information",
110
+ category="tenant",
111
+ is_system=True
112
+ ))
113
+
114
+ self.register_permission(PermissionDefinition(
115
+ code="tenant:write",
116
+ name="Write Tenant",
117
+ description="Modify tenant settings",
118
+ category="tenant",
119
+ is_system=True
120
+ ))
121
+
122
+ # User Permissions
123
+ self.register_permission(PermissionDefinition(
124
+ code="users:read",
125
+ name="Read Users",
126
+ description="View users in tenant",
127
+ category="users",
128
+ is_system=True
129
+ ))
130
+
131
+ self.register_permission(PermissionDefinition(
132
+ code="users:write",
133
+ name="Manage Users",
134
+ description="Create, update, delete users",
135
+ category="users",
136
+ is_system=True
137
+ ))
138
+
139
+ # Profile Permissions
140
+ self.register_permission(PermissionDefinition(
141
+ code="profile:read_own",
142
+ name="Read Own Profile",
143
+ description="View own profile",
144
+ category="profile",
145
+ is_system=True
146
+ ))
147
+
148
+ self.register_permission(PermissionDefinition(
149
+ code="profile:write_own",
150
+ name="Write Own Profile",
151
+ description="Update own profile",
152
+ category="profile",
153
+ is_system=True
154
+ ))
155
+
156
+ # Event Permissions
157
+ self.register_permission(PermissionDefinition(
158
+ code="events:read",
159
+ name="Read Events",
160
+ description="View events",
161
+ category="events",
162
+ is_system=True
163
+ ))
164
+
165
+ self.register_permission(PermissionDefinition(
166
+ code="events:write",
167
+ name="Write Events",
168
+ description="Create and update events",
169
+ category="events",
170
+ is_system=True
171
+ ))
172
+
173
+ self.register_permission(PermissionDefinition(
174
+ code="events:write_own",
175
+ name="Write Own Events",
176
+ description="Create and update own events only",
177
+ category="events",
178
+ is_system=True
179
+ ))
180
+
181
+ self.register_permission(PermissionDefinition(
182
+ code="events:delete",
183
+ name="Delete Events",
184
+ description="Delete events",
185
+ category="events",
186
+ is_system=True
187
+ ))
188
+
189
+ self.register_permission(PermissionDefinition(
190
+ code="events:admin",
191
+ name="Event Admin",
192
+ description="Full event management",
193
+ category="events",
194
+ is_system=True
195
+ ))
196
+
197
+ # Chat Permissions
198
+ self.register_permission(PermissionDefinition(
199
+ code="chat:read",
200
+ name="Read Chat",
201
+ description="View chat messages",
202
+ category="chat",
203
+ is_system=True
204
+ ))
205
+
206
+ self.register_permission(PermissionDefinition(
207
+ code="chat:write",
208
+ name="Send Messages",
209
+ description="Send chat messages",
210
+ category="chat",
211
+ is_system=True
212
+ ))
213
+
214
+ self.register_permission(PermissionDefinition(
215
+ code="chat:admin",
216
+ name="Chat Admin",
217
+ description="Manage channels and messages",
218
+ category="chat",
219
+ is_system=True
220
+ ))
221
+
222
+ # Community Permissions
223
+ self.register_permission(PermissionDefinition(
224
+ code="communities:read",
225
+ name="Read Communities",
226
+ description="View communities",
227
+ category="communities",
228
+ is_system=True
229
+ ))
230
+
231
+ self.register_permission(PermissionDefinition(
232
+ code="communities:write",
233
+ name="Write Communities",
234
+ description="Create and update communities",
235
+ category="communities",
236
+ is_system=True
237
+ ))
238
+
239
+ self.register_permission(PermissionDefinition(
240
+ code="communities:write_own",
241
+ name="Write Own Communities",
242
+ description="Create and update own communities only",
243
+ category="communities",
244
+ is_system=True
245
+ ))
246
+
247
+ self.register_permission(PermissionDefinition(
248
+ code="communities:admin",
249
+ name="Community Admin",
250
+ description="Full community management",
251
+ category="communities",
252
+ is_system=True
253
+ ))
254
+
255
+ # Analytics Permissions
256
+ self.register_permission(PermissionDefinition(
257
+ code="analytics:read",
258
+ name="View Analytics",
259
+ description="View analytics and reports",
260
+ category="analytics",
261
+ is_system=True
262
+ ))
263
+
264
+ # Subscription Permissions
265
+ self.register_permission(PermissionDefinition(
266
+ code="subscriptions:read",
267
+ name="Read Subscriptions",
268
+ description="View subscription information",
269
+ category="subscriptions",
270
+ is_system=True
271
+ ))
272
+
273
+ self.register_permission(PermissionDefinition(
274
+ code="subscriptions:write",
275
+ name="Manage Subscriptions",
276
+ description="Update subscription and billing",
277
+ category="subscriptions",
278
+ is_system=True
279
+ ))
280
+
281
+ # Register default roles
282
+ self._register_default_roles()
283
+
284
+ def _register_default_roles(self):
285
+ """Register default system roles."""
286
+
287
+ # Platform Admin
288
+ self.register_role(RoleDefinition(
289
+ code="platform_admin",
290
+ name="Platform Administrator",
291
+ description="Full system access across all tenants",
292
+ permissions=["platform:admin"],
293
+ scope="platform",
294
+ level=1000,
295
+ is_system=True,
296
+ is_assignable=True
297
+ ))
298
+
299
+ # Platform Support
300
+ self.register_role(RoleDefinition(
301
+ code="platform_support",
302
+ name="Platform Support",
303
+ description="Read-only access for customer support",
304
+ permissions=["platform:support", "tenant:read", "users:read"],
305
+ scope="platform",
306
+ level=500,
307
+ is_system=True,
308
+ is_assignable=True
309
+ ))
310
+
311
+ # Tenant Admin
312
+ self.register_role(RoleDefinition(
313
+ code="tenant_admin",
314
+ name="Tenant Administrator",
315
+ description="Full administrative access within tenant",
316
+ permissions=[
317
+ "tenant:admin", "tenant:read", "tenant:write",
318
+ "users:read", "users:write",
319
+ "events:admin", "chat:admin", "communities:admin",
320
+ "analytics:read", "subscriptions:read", "subscriptions:write"
321
+ ],
322
+ scope="tenant",
323
+ level=100,
324
+ is_system=True,
325
+ is_assignable=True
326
+ ))
327
+
328
+ # Event Organizer
329
+ self.register_role(RoleDefinition(
330
+ code="tenant_organizer",
331
+ name="Event Organizer",
332
+ description="Enhanced event and group management",
333
+ permissions=[
334
+ "events:admin", "communities:admin", "chat:write",
335
+ "profile:read_own", "profile:write_own"
336
+ ],
337
+ scope="tenant",
338
+ level=50,
339
+ is_system=True,
340
+ is_assignable=True
341
+ ))
342
+
343
+ # Tenant User
344
+ self.register_role(RoleDefinition(
345
+ code="tenant_user",
346
+ name="Tenant User",
347
+ description="Standard user with basic permissions",
348
+ permissions=[
349
+ "events:read", "events:write_own",
350
+ "communities:read", "communities:write_own",
351
+ "chat:read", "chat:write",
352
+ "profile:read_own", "profile:write_own"
353
+ ],
354
+ scope="tenant",
355
+ level=10,
356
+ is_system=True,
357
+ is_assignable=True
358
+ ))
359
+
360
+ # Viewer
361
+ self.register_role(RoleDefinition(
362
+ code="tenant_viewer",
363
+ name="Viewer",
364
+ description="Read-only access to tenant resources",
365
+ permissions=[
366
+ "events:read", "communities:read", "chat:read",
367
+ "profile:read_own"
368
+ ],
369
+ scope="tenant",
370
+ level=1,
371
+ is_system=True,
372
+ is_assignable=True
373
+ ))
374
+
375
+ def register_permission(self, permission: PermissionDefinition):
376
+ """
377
+ Register a new permission.
378
+
379
+ Args:
380
+ permission: Permission definition to register
381
+ """
382
+ with self._lock:
383
+ self._permissions[permission.code] = permission
384
+ self._categories.add(permission.category)
385
+
386
+ def register_role(self, role: RoleDefinition):
387
+ """
388
+ Register a new role.
389
+
390
+ Args:
391
+ role: Role definition to register
392
+ """
393
+ with self._lock:
394
+ self._roles[role.code] = role
395
+
396
+ def get_permission(self, code: str) -> Optional[PermissionDefinition]:
397
+ """Get permission by code."""
398
+ return self._permissions.get(code)
399
+
400
+ def get_role(self, code: str) -> Optional[RoleDefinition]:
401
+ """Get role by code."""
402
+ return self._roles.get(code)
403
+
404
+ def get_all_permissions(self) -> List[PermissionDefinition]:
405
+ """Get all registered permissions."""
406
+ return list(self._permissions.values())
407
+
408
+ def get_all_roles(self) -> List[RoleDefinition]:
409
+ """Get all registered roles."""
410
+ return list(self._roles.values())
411
+
412
+ def get_permissions_by_category(self, category: str) -> List[PermissionDefinition]:
413
+ """Get all permissions in a category."""
414
+ return [p for p in self._permissions.values() if p.category == category]
415
+
416
+ def get_roles_by_scope(self, scope: str) -> List[RoleDefinition]:
417
+ """Get all roles by scope (global or tenant)."""
418
+ return [r for r in self._roles.values() if r.scope == scope]
419
+
420
+ def resolve_role_permissions(self, role_code: str, resolved: Set[str] = None) -> Set[str]:
421
+ """
422
+ Resolve all permissions for a role, including inherited.
423
+
424
+ Args:
425
+ role_code: Role code to resolve
426
+ resolved: Set of already resolved permissions (for recursion)
427
+
428
+ Returns:
429
+ Set of permission codes
430
+ """
431
+ if resolved is None:
432
+ resolved = set()
433
+
434
+ role = self.get_role(role_code)
435
+ if not role:
436
+ return resolved
437
+
438
+ # Add direct permissions
439
+ resolved.update(role.permissions)
440
+
441
+ # Recursively add inherited permissions
442
+ for inherited_role in role.inherits_from:
443
+ self.resolve_role_permissions(inherited_role, resolved)
444
+
445
+ return resolved
446
+
447
+ def get_permissions_for_roles(self, role_codes: List[str]) -> List[str]:
448
+ """
449
+ Get all unique permissions for a list of roles.
450
+
451
+ Args:
452
+ role_codes: List of role codes
453
+
454
+ Returns:
455
+ List of unique permission codes
456
+ """
457
+ all_perms = set()
458
+ for role_code in role_codes:
459
+ all_perms.update(self.resolve_role_permissions(role_code))
460
+ return list(all_perms)
461
+
462
+
463
+ # Global singleton instance
464
+ permission_registry = PermissionRegistry()