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,44 @@
1
+ # src/geek_cafe_saas_sdk/lambda_handlers/subscriptions/list/app.py
2
+
3
+ from typing import Dict, Any
4
+
5
+ from geek_cafe_saas_sdk.services import SubscriptionService
6
+ from geek_cafe_saas_sdk.lambda_handlers import ServicePool
7
+ from geek_cafe_saas_sdk.utilities.response import service_result_to_response, error_response
8
+ from geek_cafe_saas_sdk.utilities.lambda_event_utility import LambdaEventUtility
9
+
10
+ subscription_service_pool = ServicePool(SubscriptionService)
11
+
12
+ def handler(event: Dict[str, Any], context: object, injected_service=None) -> Dict[str, Any]:
13
+ """
14
+ Lambda handler for listing subscription history for a tenant.
15
+
16
+ Returns all subscriptions (current and past) sorted by date descending.
17
+
18
+ Query parameters:
19
+ - limit: Maximum number of results (default: 50)
20
+
21
+ Args:
22
+ event: API Gateway event
23
+ context: Lambda context
24
+ injected_service: Optional SubscriptionService for testing
25
+ """
26
+ try:
27
+ subscription_service = injected_service if injected_service else subscription_service_pool.get()
28
+ user_id = LambdaEventUtility.get_authenticated_user_id(event)
29
+ tenant_id = LambdaEventUtility.get_authenticated_user_tenant_id(event)
30
+ query_params = event.get('queryStringParameters', {}) or {}
31
+
32
+ # Get limit from query params (default 50)
33
+ limit = int(query_params.get('limit', 50))
34
+
35
+ result = subscription_service.list_subscription_history(
36
+ tenant_id=tenant_id,
37
+ user_id=user_id,
38
+ limit=limit
39
+ )
40
+
41
+ return service_result_to_response(result)
42
+
43
+ except Exception as e:
44
+ return error_response(f"An unexpected error occurred: {str(e)}", "INTERNAL_ERROR", 500)
@@ -0,0 +1,56 @@
1
+ # src/geek_cafe_saas_sdk/lambda_handlers/subscriptions/record_payment/app.py
2
+
3
+ import json
4
+ from typing import Dict, Any
5
+
6
+ from geek_cafe_saas_sdk.services import SubscriptionService
7
+ from geek_cafe_saas_sdk.lambda_handlers import ServicePool
8
+ from geek_cafe_saas_sdk.utilities.response import service_result_to_response, error_response
9
+ from geek_cafe_saas_sdk.utilities.lambda_event_utility import LambdaEventUtility
10
+
11
+ subscription_service_pool = ServicePool(SubscriptionService)
12
+
13
+ def handler(event: Dict[str, Any], context: object, injected_service=None) -> Dict[str, Any]:
14
+ """
15
+ Lambda handler for recording a payment on a subscription.
16
+
17
+ This updates the subscription with payment details and can change status from past_due to active.
18
+
19
+ Expected body:
20
+ {
21
+ "amount_cents": 2999
22
+ }
23
+
24
+ Args:
25
+ event: API Gateway event
26
+ context: Lambda context
27
+ injected_service: Optional SubscriptionService for testing
28
+ """
29
+ try:
30
+ subscription_service = injected_service if injected_service else subscription_service_pool.get()
31
+ body = LambdaEventUtility.get_body_from_event(event)
32
+ user_id = LambdaEventUtility.get_authenticated_user_id(event)
33
+ tenant_id = LambdaEventUtility.get_authenticated_user_tenant_id(event)
34
+ resource_id = LambdaEventUtility.get_value_from_path_parameters(event, 'id')
35
+
36
+ if not resource_id:
37
+ return error_response("Subscription ID is required in the path.", "VALIDATION_ERROR", 400)
38
+
39
+ # Get payment amount
40
+ amount_cents = body.get('amount_cents')
41
+ if amount_cents is None:
42
+ return error_response("Payment amount_cents is required.", "VALIDATION_ERROR", 400)
43
+
44
+ result = subscription_service.record_payment(
45
+ subscription_id=resource_id,
46
+ tenant_id=tenant_id,
47
+ user_id=user_id,
48
+ amount_cents=amount_cents
49
+ )
50
+
51
+ return service_result_to_response(result)
52
+
53
+ except json.JSONDecodeError:
54
+ return error_response("Invalid JSON in request body.", "VALIDATION_ERROR", 400)
55
+ except Exception as e:
56
+ return error_response(f"An unexpected error occurred: {str(e)}", "INTERNAL_ERROR", 500)
@@ -0,0 +1,39 @@
1
+ # src/geek_cafe_saas_sdk/lambda_handlers/tenants/get/app.py
2
+
3
+ from typing import Dict, Any
4
+
5
+ from geek_cafe_saas_sdk.services import TenantService
6
+ from geek_cafe_saas_sdk.lambda_handlers import ServicePool
7
+ from geek_cafe_saas_sdk.utilities.response import service_result_to_response, error_response
8
+ from geek_cafe_saas_sdk.utilities.lambda_event_utility import LambdaEventUtility
9
+
10
+ tenant_service_pool = ServicePool(TenantService)
11
+
12
+ def handler(event: Dict[str, Any], context: object, injected_service=None) -> Dict[str, Any]:
13
+ """
14
+ Lambda handler for retrieving a tenant by ID.
15
+
16
+ Args:
17
+ event: API Gateway event
18
+ context: Lambda context
19
+ injected_service: Optional TenantService for testing
20
+ """
21
+ try:
22
+ tenant_service = injected_service if injected_service else tenant_service_pool.get()
23
+ user_id = LambdaEventUtility.get_authenticated_user_id(event)
24
+ tenant_id = LambdaEventUtility.get_authenticated_user_tenant_id(event)
25
+ resource_id = LambdaEventUtility.get_value_from_path_parameters(event, 'id')
26
+
27
+ if not resource_id:
28
+ return error_response("Tenant ID is required in the path.", "VALIDATION_ERROR", 400)
29
+
30
+ result = tenant_service.get_by_id(
31
+ resource_id=resource_id,
32
+ tenant_id=tenant_id,
33
+ user_id=user_id
34
+ )
35
+
36
+ return service_result_to_response(result)
37
+
38
+ except Exception as e:
39
+ return error_response(f"An unexpected error occurred: {str(e)}", "INTERNAL_ERROR", 500)
@@ -0,0 +1,37 @@
1
+ # src/geek_cafe_saas_sdk/lambda_handlers/tenants/me/app.py
2
+
3
+ from typing import Dict, Any
4
+
5
+ from geek_cafe_saas_sdk.services import TenantService
6
+ from geek_cafe_saas_sdk.lambda_handlers import ServicePool
7
+ from geek_cafe_saas_sdk.utilities.response import service_result_to_response, error_response
8
+ from geek_cafe_saas_sdk.utilities.lambda_event_utility import LambdaEventUtility
9
+
10
+ tenant_service_pool = ServicePool(TenantService)
11
+
12
+ def handler(event: Dict[str, Any], context: object, injected_service=None) -> Dict[str, Any]:
13
+ """
14
+ Lambda handler for retrieving the authenticated user's tenant.
15
+
16
+ This is a convenience endpoint for /tenants/me to get the current user's tenant.
17
+
18
+ Args:
19
+ event: API Gateway event
20
+ context: Lambda context
21
+ injected_service: Optional TenantService for testing
22
+ """
23
+ try:
24
+ tenant_service = injected_service if injected_service else tenant_service_pool.get()
25
+ user_id = LambdaEventUtility.get_authenticated_user_id(event)
26
+ tenant_id = LambdaEventUtility.get_authenticated_user_tenant_id(event)
27
+
28
+ result = tenant_service.get_by_id(
29
+ resource_id=tenant_id,
30
+ tenant_id=tenant_id,
31
+ user_id=user_id
32
+ )
33
+
34
+ return service_result_to_response(result)
35
+
36
+ except Exception as e:
37
+ return error_response(f"An unexpected error occurred: {str(e)}", "INTERNAL_ERROR", 500)
@@ -0,0 +1,61 @@
1
+ # src/geek_cafe_saas_sdk/lambda_handlers/tenants/signup/app.py
2
+
3
+ import json
4
+ from typing import Dict, Any
5
+
6
+ from geek_cafe_saas_sdk.services import TenantService
7
+ from geek_cafe_saas_sdk.lambda_handlers import ServicePool
8
+ from geek_cafe_saas_sdk.utilities.response import service_result_to_response, error_response
9
+ from geek_cafe_saas_sdk.utilities.lambda_event_utility import LambdaEventUtility
10
+
11
+ tenant_service_pool = ServicePool(TenantService)
12
+
13
+ def handler(event: Dict[str, Any], context: object, injected_service=None) -> Dict[str, Any]:
14
+ """
15
+ Lambda handler for tenant signup (creates tenant + primary admin user).
16
+
17
+ This is the initial signup endpoint that creates both a tenant and its first admin user.
18
+
19
+ Expected body:
20
+ {
21
+ "user": {
22
+ "email": "admin@company.com",
23
+ "first_name": "John",
24
+ "last_name": "Doe"
25
+ },
26
+ "tenant": {
27
+ "name": "Company Name"
28
+ }
29
+ }
30
+
31
+ Args:
32
+ event: API Gateway event
33
+ context: Lambda context
34
+ injected_service: Optional TenantService for testing
35
+ """
36
+ try:
37
+ tenant_service = injected_service if injected_service else tenant_service_pool.get()
38
+ body = LambdaEventUtility.get_body_from_event(event)
39
+
40
+ # Extract user and tenant payloads
41
+ user_payload = body.get('user', {})
42
+ tenant_payload = body.get('tenant', {})
43
+
44
+ if not user_payload:
45
+ return error_response("User information is required.", "VALIDATION_ERROR", 400)
46
+
47
+ if not tenant_payload:
48
+ return error_response("Tenant information is required.", "VALIDATION_ERROR", 400)
49
+
50
+ # Create tenant with user (signup flow)
51
+ result = tenant_service.create_with_user(
52
+ user_payload=user_payload,
53
+ tenant_payload=tenant_payload
54
+ )
55
+
56
+ return service_result_to_response(result, success_status=201)
57
+
58
+ except json.JSONDecodeError:
59
+ return error_response("Invalid JSON in request body.", "VALIDATION_ERROR", 400)
60
+ except Exception as e:
61
+ return error_response(f"An unexpected error occurred: {str(e)}", "INTERNAL_ERROR", 500)
@@ -0,0 +1,44 @@
1
+ # src/geek_cafe_saas_sdk/lambda_handlers/tenants/update/app.py
2
+
3
+ import json
4
+ from typing import Dict, Any
5
+
6
+ from geek_cafe_saas_sdk.services import TenantService
7
+ from geek_cafe_saas_sdk.lambda_handlers import ServicePool
8
+ from geek_cafe_saas_sdk.utilities.response import service_result_to_response, error_response
9
+ from geek_cafe_saas_sdk.utilities.lambda_event_utility import LambdaEventUtility
10
+
11
+ tenant_service_pool = ServicePool(TenantService)
12
+
13
+ def handler(event: Dict[str, Any], context: object, injected_service=None) -> Dict[str, Any]:
14
+ """
15
+ Lambda handler for updating a tenant.
16
+
17
+ Args:
18
+ event: API Gateway event
19
+ context: Lambda context
20
+ injected_service: Optional TenantService for testing
21
+ """
22
+ try:
23
+ tenant_service = injected_service if injected_service else tenant_service_pool.get()
24
+ body = LambdaEventUtility.get_body_from_event(event)
25
+ user_id = LambdaEventUtility.get_authenticated_user_id(event)
26
+ tenant_id = LambdaEventUtility.get_authenticated_user_tenant_id(event)
27
+ resource_id = LambdaEventUtility.get_value_from_path_parameters(event, 'id')
28
+
29
+ if not resource_id:
30
+ return error_response("Tenant ID is required in the path.", "VALIDATION_ERROR", 400)
31
+
32
+ result = tenant_service.update(
33
+ resource_id=resource_id,
34
+ tenant_id=tenant_id,
35
+ user_id=user_id,
36
+ updates=body
37
+ )
38
+
39
+ return service_result_to_response(result)
40
+
41
+ except json.JSONDecodeError:
42
+ return error_response("Invalid JSON in request body.", "VALIDATION_ERROR", 400)
43
+ except Exception as e:
44
+ return error_response(f"An unexpected error occurred: {str(e)}", "INTERNAL_ERROR", 500)
@@ -0,0 +1,6 @@
1
+ # Tenancy Domain Models
2
+
3
+ from .tenant import Tenant
4
+ from .subscription import Subscription
5
+
6
+ __all__ = ["Tenant", "Subscription"]