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,64 @@
1
+ """
2
+ Lambda handler for getting a chat channel by ID.
3
+
4
+ Requires authentication.
5
+ """
6
+
7
+ from typing import Dict, Any
8
+ from geek_cafe_saas_sdk.lambda_handlers import create_handler
9
+ from geek_cafe_saas_sdk.domains.messaging.services import ChatChannelService
10
+
11
+ # Factory creates handler (defaults to secure auth)
12
+ handler_wrapper = create_handler(
13
+ service_class=ChatChannelService,
14
+ require_body=False
15
+ )
16
+
17
+
18
+ def handler(event: Dict[str, Any], context: Any, injected_service=None) -> Dict[str, Any]:
19
+ """
20
+ Get a chat channel by ID.
21
+
22
+ Args:
23
+ event: Lambda event from API Gateway
24
+ context: Lambda context
25
+ injected_service: Optional ChatChannelService for testing
26
+
27
+ Path parameters:
28
+ id: Chat channel ID
29
+
30
+ Returns 200 with chat channel details
31
+ """
32
+ return handler_wrapper.execute(event, context, get_chat_channel, injected_service)
33
+
34
+
35
+ def get_chat_channel(
36
+ event: Dict[str, Any],
37
+ service: ChatChannelService,
38
+ user_context: Dict[str, str]
39
+ ) -> Any:
40
+ """
41
+ Business logic for getting a chat channel.
42
+
43
+ Access control: public channels visible to all, private channels only to members.
44
+ """
45
+ # Extract path parameter
46
+ path_params = event.get("pathParameters") or {}
47
+ channel_id = path_params.get("id")
48
+
49
+ if not channel_id:
50
+ from geek_cafe_saas_sdk.core.service_result import ServiceResult
51
+ from geek_cafe_saas_sdk.core.service_errors import ValidationError
52
+ return ServiceResult.exception_result(
53
+ ValidationError("Channel ID is required in path")
54
+ )
55
+
56
+ user_id = user_context.get("user_id")
57
+ tenant_id = user_context.get("tenant_id")
58
+
59
+ # Get the chat channel with access control
60
+ return service.get_by_id(
61
+ resource_id=channel_id,
62
+ tenant_id=tenant_id,
63
+ user_id=user_id
64
+ )
@@ -0,0 +1,97 @@
1
+ """
2
+ Lambda handler for listing chat channels.
3
+
4
+ Supports multiple query patterns:
5
+ - List by channel type (public, private, direct)
6
+ - List user's channels
7
+ - List default channels
8
+ """
9
+
10
+ from typing import Dict, Any
11
+ from geek_cafe_saas_sdk.lambda_handlers import create_handler
12
+ from geek_cafe_saas_sdk.domains.messaging.services import ChatChannelService
13
+
14
+ # Factory creates handler (defaults to secure auth)
15
+ handler_wrapper = create_handler(
16
+ service_class=ChatChannelService,
17
+ require_body=False
18
+ )
19
+
20
+
21
+ def handler(event: Dict[str, Any], context: Any, injected_service=None) -> Dict[str, Any]:
22
+ """
23
+ List chat channels based on query parameters.
24
+
25
+ Args:
26
+ event: Lambda event from API Gateway
27
+ context: Lambda context
28
+ injected_service: Optional ChatChannelService for testing
29
+
30
+ Query parameters:
31
+ channel_type: Filter by type (public, private, direct)
32
+ user_channels: "true" to get only user's channels
33
+ default: "true" to get only default channels
34
+ include_archived: "true" to include archived channels
35
+ limit: Maximum number of results (default 50)
36
+
37
+ Examples:
38
+ GET /chat-channels?channel_type=public
39
+ GET /chat-channels?user_channels=true
40
+ GET /chat-channels?default=true
41
+
42
+ Returns 200 with list of chat channels
43
+ """
44
+ return handler_wrapper.execute(event, context, list_chat_channels, injected_service)
45
+
46
+
47
+ def list_chat_channels(
48
+ event: Dict[str, Any],
49
+ service: ChatChannelService,
50
+ user_context: Dict[str, str]
51
+ ) -> Any:
52
+ """
53
+ Business logic for listing chat channels.
54
+
55
+ Routes to different service methods based on query parameters.
56
+ """
57
+ query_params = event.get("queryStringParameters") or {}
58
+
59
+ user_id = user_context.get("user_id")
60
+ tenant_id = user_context.get("tenant_id")
61
+ limit = int(query_params.get("limit", "100"))
62
+
63
+ # Route to appropriate service method
64
+
65
+ # Pattern 1: List default channels
66
+ if query_params.get("default") == "true":
67
+ return service.list_default_channels(
68
+ tenant_id=tenant_id,
69
+ limit=limit
70
+ )
71
+
72
+ # Pattern 2: List user's channels
73
+ if query_params.get("user_channels") == "true":
74
+ include_archived = query_params.get("include_archived") == "true"
75
+ return service.list_user_channels(
76
+ tenant_id=tenant_id,
77
+ user_id=user_id,
78
+ include_archived=include_archived,
79
+ limit=limit
80
+ )
81
+
82
+ # Pattern 3: List by channel type
83
+ if "channel_type" in query_params:
84
+ channel_type = query_params.get("channel_type")
85
+ return service.list_by_type(
86
+ tenant_id=tenant_id,
87
+ channel_type=channel_type,
88
+ user_id=user_id,
89
+ limit=limit
90
+ )
91
+
92
+ # Pattern 4: List all accessible channels (default)
93
+ return service.list_all(
94
+ tenant_id=tenant_id,
95
+ user_id=user_id,
96
+ limit=limit
97
+ )
@@ -0,0 +1,149 @@
1
+ """
2
+ Lambda handler for updating chat channels.
3
+
4
+ Supports multiple operations:
5
+ - Update channel properties
6
+ - Add/remove members
7
+ - Archive/unarchive
8
+ """
9
+
10
+ from typing import Dict, Any
11
+ from geek_cafe_saas_sdk.lambda_handlers import create_handler
12
+ from geek_cafe_saas_sdk.domains.messaging.services import ChatChannelService
13
+
14
+ # Factory creates handler (defaults to secure auth)
15
+ handler_wrapper = create_handler(
16
+ service_class=ChatChannelService,
17
+ require_body=True,
18
+ convert_case=True
19
+ )
20
+
21
+
22
+ def handler(event: Dict[str, Any], context: Any, injected_service=None) -> Dict[str, Any]:
23
+ """
24
+ Update a chat channel.
25
+
26
+ Args:
27
+ event: Lambda event from API Gateway
28
+ context: Lambda context
29
+ injected_service: Optional ChatChannelService for testing
30
+
31
+ Path parameters:
32
+ id: Chat channel ID
33
+
34
+ Expected body (camelCase from frontend):
35
+ {
36
+ "action": "update" | "add_member" | "remove_member" | "archive" | "unarchive",
37
+
38
+ // For action="update":
39
+ "name": "Updated Name",
40
+ "description": "Updated description",
41
+ "topic": "New topic",
42
+ "isAnnouncement": true,
43
+
44
+ // For action="add_member":
45
+ "memberId": "user_456",
46
+
47
+ // For action="remove_member":
48
+ "memberId": "user_456"
49
+ }
50
+
51
+ Returns 200 with updated chat channel
52
+ """
53
+ return handler_wrapper.execute(event, context, update_chat_channel, injected_service)
54
+
55
+
56
+ def update_chat_channel(
57
+ event: Dict[str, Any],
58
+ service: ChatChannelService,
59
+ user_context: Dict[str, str]
60
+ ) -> Any:
61
+ """
62
+ Business logic for updating chat channels.
63
+
64
+ Routes to different service methods based on action parameter.
65
+ """
66
+ # Extract path parameter
67
+ path_params = event.get("pathParameters") or {}
68
+ channel_id = path_params.get("id")
69
+
70
+ if not channel_id:
71
+ from geek_cafe_saas_sdk.core.service_result import ServiceResult
72
+ from geek_cafe_saas_sdk.core.service_errors import ValidationError
73
+ return ServiceResult.exception_result(
74
+ ValidationError("Channel ID is required in path")
75
+ )
76
+
77
+ payload = event["parsed_body"]
78
+ action = payload.get("action", "update")
79
+
80
+ user_id = user_context.get("user_id")
81
+ tenant_id = user_context.get("tenant_id")
82
+
83
+ # Route to appropriate service method based on action
84
+
85
+ if action == "add_member":
86
+ # Add a member to the channel
87
+ member_id = payload.get("member_id")
88
+ if not member_id:
89
+ from geek_cafe_saas_sdk.core.service_result import ServiceResult
90
+ from geek_cafe_saas_sdk.core.service_errors import ValidationError
91
+ return ServiceResult.exception_result(
92
+ ValidationError("member_id is required for add_member action")
93
+ )
94
+
95
+ return service.add_member(
96
+ channel_id=channel_id,
97
+ tenant_id=tenant_id,
98
+ user_id=user_id,
99
+ member_to_add=member_id
100
+ )
101
+
102
+ elif action == "remove_member":
103
+ # Remove a member from the channel
104
+ member_id = payload.get("member_id")
105
+ if not member_id:
106
+ from geek_cafe_saas_sdk.core.service_result import ServiceResult
107
+ from geek_cafe_saas_sdk.core.service_errors import ValidationError
108
+ return ServiceResult.exception_result(
109
+ ValidationError("member_id is required for remove_member action")
110
+ )
111
+
112
+ return service.remove_member(
113
+ channel_id=channel_id,
114
+ tenant_id=tenant_id,
115
+ user_id=user_id,
116
+ member_to_remove=member_id
117
+ )
118
+
119
+ elif action == "archive":
120
+ # Archive the channel
121
+ return service.archive(
122
+ channel_id=channel_id,
123
+ tenant_id=tenant_id,
124
+ user_id=user_id
125
+ )
126
+
127
+ elif action == "unarchive":
128
+ # Unarchive the channel
129
+ return service.unarchive(
130
+ channel_id=channel_id,
131
+ tenant_id=tenant_id,
132
+ user_id=user_id
133
+ )
134
+
135
+ else:
136
+ # General update (update channel properties)
137
+ updates = {}
138
+ allowed_fields = ['name', 'description', 'topic', 'icon', 'is_announcement', 'is_default']
139
+
140
+ for field in allowed_fields:
141
+ if field in payload:
142
+ updates[field] = payload[field]
143
+
144
+ return service.update(
145
+ resource_id=channel_id,
146
+ tenant_id=tenant_id,
147
+ user_id=user_id,
148
+ updates=updates
149
+ )
@@ -0,0 +1,67 @@
1
+ """
2
+ Lambda handler for creating chat messages.
3
+
4
+ Requires authentication.
5
+ """
6
+
7
+ from typing import Dict, Any
8
+ from geek_cafe_saas_sdk.lambda_handlers import create_handler
9
+ from geek_cafe_saas_sdk.domains.messaging.services import ChatMessageService
10
+
11
+ # Factory creates handler (defaults to secure auth)
12
+ handler_wrapper = create_handler(
13
+ service_class=ChatMessageService,
14
+ require_body=True,
15
+ convert_case=True
16
+ )
17
+
18
+
19
+ def handler(event: Dict[str, Any], context: Any, injected_service=None) -> Dict[str, Any]:
20
+ """
21
+ Create a new chat message.
22
+
23
+ Args:
24
+ event: Lambda event from API Gateway
25
+ context: Lambda context
26
+ injected_service: Optional ChatMessageService for testing
27
+
28
+ Expected body (camelCase from frontend):
29
+ {
30
+ "channelId": "channel_123",
31
+ "content": "Hello world!",
32
+ "senderName": "User Name",
33
+ "parentMessageId": "msg_parent_123" (optional for threaded replies),
34
+ "mentions": ["user_456", "user_789"],
35
+ "attachments": [
36
+ {"type": "image", "url": "https://..."}
37
+ ]
38
+ }
39
+
40
+ Returns 201 with created chat message
41
+ """
42
+ return handler_wrapper.execute(event, context, create_chat_message, injected_service)
43
+
44
+
45
+ def create_chat_message(
46
+ event: Dict[str, Any],
47
+ service: ChatMessageService,
48
+ user_context: Dict[str, str]
49
+ ) -> Any:
50
+ """
51
+ Business logic for creating chat messages.
52
+
53
+ Validates channel membership before creating message.
54
+ """
55
+ payload = event["parsed_body"]
56
+
57
+ user_id = user_context.get("user_id")
58
+ tenant_id = user_context.get("tenant_id")
59
+
60
+ # Create the chat message
61
+ result = service.create(
62
+ tenant_id=tenant_id,
63
+ user_id=user_id,
64
+ payload=payload
65
+ )
66
+
67
+ return result
@@ -0,0 +1,65 @@
1
+ """
2
+ Lambda handler for deleting (soft delete) chat messages.
3
+
4
+ Requires authentication. Only message sender can delete.
5
+ """
6
+
7
+ from typing import Dict, Any
8
+ from geek_cafe_saas_sdk.lambda_handlers import create_handler
9
+ from geek_cafe_saas_sdk.domains.messaging.services import ChatMessageService
10
+
11
+ # Factory creates handler (defaults to secure auth)
12
+ handler_wrapper = create_handler(
13
+ service_class=ChatMessageService,
14
+ require_body=False
15
+ )
16
+
17
+
18
+ def handler(event: Dict[str, Any], context: Any, injected_service=None) -> Dict[str, Any]:
19
+ """
20
+ Delete (soft delete) a chat message.
21
+
22
+ Args:
23
+ event: Lambda event from API Gateway
24
+ context: Lambda context
25
+ injected_service: Optional ChatMessageService for testing
26
+
27
+ Path parameters:
28
+ id: Chat message ID
29
+
30
+ Returns 200 with success boolean
31
+ """
32
+ return handler_wrapper.execute(event, context, delete_chat_message, injected_service)
33
+
34
+
35
+ def delete_chat_message(
36
+ event: Dict[str, Any],
37
+ service: ChatMessageService,
38
+ user_context: Dict[str, str]
39
+ ) -> Any:
40
+ """
41
+ Business logic for deleting a chat message.
42
+
43
+ Performs soft delete (sets deleted timestamp).
44
+ Only message sender can delete.
45
+ """
46
+ # Extract path parameter
47
+ path_params = event.get("pathParameters") or {}
48
+ message_id = path_params.get("id")
49
+
50
+ if not message_id:
51
+ from geek_cafe_saas_sdk.core.service_result import ServiceResult
52
+ from geek_cafe_saas_sdk.core.service_errors import ValidationError
53
+ return ServiceResult.exception_result(
54
+ ValidationError("Message ID is required in path")
55
+ )
56
+
57
+ user_id = user_context.get("user_id")
58
+ tenant_id = user_context.get("tenant_id")
59
+
60
+ # Delete the chat message
61
+ return service.delete(
62
+ resource_id=message_id,
63
+ tenant_id=tenant_id,
64
+ user_id=user_id
65
+ )
@@ -0,0 +1,64 @@
1
+ """
2
+ Lambda handler for getting a chat message by ID.
3
+
4
+ Requires authentication and channel access.
5
+ """
6
+
7
+ from typing import Dict, Any
8
+ from geek_cafe_saas_sdk.lambda_handlers import create_handler
9
+ from geek_cafe_saas_sdk.domains.messaging.services import ChatMessageService
10
+
11
+ # Factory creates handler (defaults to secure auth)
12
+ handler_wrapper = create_handler(
13
+ service_class=ChatMessageService,
14
+ require_body=False
15
+ )
16
+
17
+
18
+ def handler(event: Dict[str, Any], context: Any, injected_service=None) -> Dict[str, Any]:
19
+ """
20
+ Get a chat message by ID.
21
+
22
+ Args:
23
+ event: Lambda event from API Gateway
24
+ context: Lambda context
25
+ injected_service: Optional ChatMessageService for testing
26
+
27
+ Path parameters:
28
+ id: Chat message ID
29
+
30
+ Returns 200 with chat message details
31
+ """
32
+ return handler_wrapper.execute(event, context, get_chat_message, injected_service)
33
+
34
+
35
+ def get_chat_message(
36
+ event: Dict[str, Any],
37
+ service: ChatMessageService,
38
+ user_context: Dict[str, str]
39
+ ) -> Any:
40
+ """
41
+ Business logic for getting a chat message.
42
+
43
+ Verifies user has access to the channel before returning message.
44
+ """
45
+ # Extract path parameter
46
+ path_params = event.get("pathParameters") or {}
47
+ message_id = path_params.get("id")
48
+
49
+ if not message_id:
50
+ from geek_cafe_saas_sdk.core.service_result import ServiceResult
51
+ from geek_cafe_saas_sdk.core.service_errors import ValidationError
52
+ return ServiceResult.exception_result(
53
+ ValidationError("Message ID is required in path")
54
+ )
55
+
56
+ user_id = user_context.get("user_id")
57
+ tenant_id = user_context.get("tenant_id")
58
+
59
+ # Get the chat message with access control
60
+ return service.get_by_id(
61
+ resource_id=message_id,
62
+ tenant_id=tenant_id,
63
+ user_id=user_id
64
+ )
@@ -0,0 +1,102 @@
1
+ """
2
+ Lambda handler for listing chat messages.
3
+
4
+ Supports multiple query patterns:
5
+ - List messages in a channel (with pagination)
6
+ - List threaded replies to a message
7
+ - List user's message history
8
+ """
9
+
10
+ from typing import Dict, Any
11
+ from geek_cafe_saas_sdk.lambda_handlers import create_handler
12
+ from geek_cafe_saas_sdk.domains.messaging.services import ChatMessageService
13
+
14
+ # Factory creates handler (defaults to secure auth)
15
+ handler_wrapper = create_handler(
16
+ service_class=ChatMessageService,
17
+ require_body=False
18
+ )
19
+
20
+
21
+ def handler(event: Dict[str, Any], context: Any, injected_service=None) -> Dict[str, Any]:
22
+ """
23
+ List chat messages based on query parameters.
24
+
25
+ Args:
26
+ event: Lambda event from API Gateway
27
+ context: Lambda context
28
+ injected_service: Optional ChatMessageService for testing
29
+
30
+ Query parameters:
31
+ channel_id: Channel ID to list messages from
32
+ parent_message_id: Parent message ID to list thread replies
33
+ sender_id: User ID to list message history
34
+ limit: Maximum number of results (default 50)
35
+ ascending: "true" for oldest first, "false" for newest first
36
+
37
+ Examples:
38
+ GET /chat-messages?channel_id=channel_123&limit=50
39
+ GET /chat-messages?parent_message_id=msg_123
40
+ GET /chat-messages?sender_id=user_123
41
+
42
+ Returns 200 with list of chat messages
43
+ """
44
+ return handler_wrapper.execute(event, context, list_chat_messages, injected_service)
45
+
46
+
47
+ def list_chat_messages(
48
+ event: Dict[str, Any],
49
+ service: ChatMessageService,
50
+ user_context: Dict[str, str]
51
+ ) -> Any:
52
+ """
53
+ Business logic for listing chat messages.
54
+
55
+ Routes to different service methods based on query parameters.
56
+ """
57
+ query_params = event.get("queryStringParameters") or {}
58
+
59
+ user_id = user_context.get("user_id")
60
+ tenant_id = user_context.get("tenant_id")
61
+ limit = int(query_params.get("limit", "50"))
62
+ ascending = query_params.get("ascending", "true") == "true"
63
+
64
+ # Route to appropriate service method
65
+
66
+ # Pattern 1: List threaded replies to a parent message
67
+ if "parent_message_id" in query_params:
68
+ parent_message_id = query_params.get("parent_message_id")
69
+ return service.list_thread_replies(
70
+ parent_message_id=parent_message_id,
71
+ tenant_id=tenant_id,
72
+ user_id=user_id,
73
+ limit=limit
74
+ )
75
+
76
+ # Pattern 2: List user's message history
77
+ if "sender_id" in query_params:
78
+ sender_id = query_params.get("sender_id")
79
+ return service.list_by_sender(
80
+ sender_id=sender_id,
81
+ tenant_id=tenant_id,
82
+ user_id=user_id,
83
+ limit=limit
84
+ )
85
+
86
+ # Pattern 3: List messages in a channel (default, most common)
87
+ if "channel_id" in query_params:
88
+ channel_id = query_params.get("channel_id")
89
+ return service.list_by_channel(
90
+ channel_id=channel_id,
91
+ tenant_id=tenant_id,
92
+ user_id=user_id,
93
+ limit=limit,
94
+ ascending=ascending
95
+ )
96
+
97
+ # No valid query parameters
98
+ from geek_cafe_saas_sdk.core.service_result import ServiceResult
99
+ from geek_cafe_saas_sdk.core.service_errors import ValidationError
100
+ return ServiceResult.exception_result(
101
+ ValidationError("Must provide channel_id, parent_message_id, or sender_id")
102
+ )