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.
- geek_cafe_saas_sdk/__init__.py +9 -0
- geek_cafe_saas_sdk/core/__init__.py +11 -0
- geek_cafe_saas_sdk/core/audit_mixin.py +33 -0
- geek_cafe_saas_sdk/core/error_codes.py +132 -0
- geek_cafe_saas_sdk/core/service_errors.py +19 -0
- geek_cafe_saas_sdk/core/service_result.py +121 -0
- geek_cafe_saas_sdk/decorators/__init__.py +64 -0
- geek_cafe_saas_sdk/decorators/auth.py +373 -0
- geek_cafe_saas_sdk/decorators/core.py +358 -0
- geek_cafe_saas_sdk/domains/__init__.py +0 -0
- geek_cafe_saas_sdk/domains/analytics/__init__.py +0 -0
- geek_cafe_saas_sdk/domains/analytics/handlers/__init__.py +0 -0
- geek_cafe_saas_sdk/domains/analytics/models/__init__.py +9 -0
- geek_cafe_saas_sdk/domains/analytics/models/website_analytics.py +219 -0
- geek_cafe_saas_sdk/domains/analytics/models/website_analytics_summary.py +220 -0
- geek_cafe_saas_sdk/domains/analytics/services/__init__.py +11 -0
- geek_cafe_saas_sdk/domains/analytics/services/website_analytics_service.py +232 -0
- geek_cafe_saas_sdk/domains/analytics/services/website_analytics_summary_service.py +212 -0
- geek_cafe_saas_sdk/domains/analytics/services/website_analytics_tally_service.py +610 -0
- geek_cafe_saas_sdk/domains/auth/__init__.py +0 -0
- geek_cafe_saas_sdk/domains/auth/handlers/__init__.py +0 -0
- geek_cafe_saas_sdk/domains/auth/handlers/users/create/app.py +41 -0
- geek_cafe_saas_sdk/domains/auth/handlers/users/delete/app.py +41 -0
- geek_cafe_saas_sdk/domains/auth/handlers/users/get/app.py +39 -0
- geek_cafe_saas_sdk/domains/auth/handlers/users/list/app.py +36 -0
- geek_cafe_saas_sdk/domains/auth/handlers/users/update/app.py +44 -0
- geek_cafe_saas_sdk/domains/auth/models/__init__.py +13 -0
- geek_cafe_saas_sdk/domains/auth/models/permission.py +134 -0
- geek_cafe_saas_sdk/domains/auth/models/resource_permission.py +245 -0
- geek_cafe_saas_sdk/domains/auth/models/role.py +213 -0
- geek_cafe_saas_sdk/domains/auth/models/user.py +285 -0
- geek_cafe_saas_sdk/domains/auth/services/__init__.py +16 -0
- geek_cafe_saas_sdk/domains/auth/services/authorization_service.py +376 -0
- geek_cafe_saas_sdk/domains/auth/services/permission_registry.py +464 -0
- geek_cafe_saas_sdk/domains/auth/services/resource_permission_service.py +408 -0
- geek_cafe_saas_sdk/domains/auth/services/user_service.py +274 -0
- geek_cafe_saas_sdk/domains/communities/__init__.py +0 -0
- geek_cafe_saas_sdk/domains/communities/handlers/__init__.py +0 -0
- geek_cafe_saas_sdk/domains/communities/handlers/communities/create/app.py +41 -0
- geek_cafe_saas_sdk/domains/communities/handlers/communities/delete/app.py +41 -0
- geek_cafe_saas_sdk/domains/communities/handlers/communities/get/app.py +39 -0
- geek_cafe_saas_sdk/domains/communities/handlers/communities/list/app.py +36 -0
- geek_cafe_saas_sdk/domains/communities/handlers/communities/update/app.py +44 -0
- geek_cafe_saas_sdk/domains/communities/models/__init__.py +6 -0
- geek_cafe_saas_sdk/domains/communities/models/community.py +326 -0
- geek_cafe_saas_sdk/domains/communities/models/community_member.py +227 -0
- geek_cafe_saas_sdk/domains/communities/services/__init__.py +6 -0
- geek_cafe_saas_sdk/domains/communities/services/community_member_service.py +412 -0
- geek_cafe_saas_sdk/domains/communities/services/community_service.py +479 -0
- geek_cafe_saas_sdk/domains/events/__init__.py +0 -0
- geek_cafe_saas_sdk/domains/events/handlers/__init__.py +0 -0
- geek_cafe_saas_sdk/domains/events/handlers/attendees/app.py +67 -0
- geek_cafe_saas_sdk/domains/events/handlers/cancel/app.py +66 -0
- geek_cafe_saas_sdk/domains/events/handlers/check_in/app.py +60 -0
- geek_cafe_saas_sdk/domains/events/handlers/create/app.py +93 -0
- geek_cafe_saas_sdk/domains/events/handlers/delete/app.py +42 -0
- geek_cafe_saas_sdk/domains/events/handlers/get/app.py +39 -0
- geek_cafe_saas_sdk/domains/events/handlers/invite/app.py +98 -0
- geek_cafe_saas_sdk/domains/events/handlers/list/app.py +125 -0
- geek_cafe_saas_sdk/domains/events/handlers/publish/app.py +49 -0
- geek_cafe_saas_sdk/domains/events/handlers/rsvp/app.py +83 -0
- geek_cafe_saas_sdk/domains/events/handlers/update/app.py +44 -0
- geek_cafe_saas_sdk/domains/events/models/__init__.py +3 -0
- geek_cafe_saas_sdk/domains/events/models/event.py +681 -0
- geek_cafe_saas_sdk/domains/events/models/event_attendee.py +324 -0
- geek_cafe_saas_sdk/domains/events/services/__init__.py +9 -0
- geek_cafe_saas_sdk/domains/events/services/event_attendee_service.py +571 -0
- geek_cafe_saas_sdk/domains/events/services/event_service.py +684 -0
- geek_cafe_saas_sdk/domains/files/__init__.py +0 -0
- geek_cafe_saas_sdk/domains/files/models/__init__.py +0 -0
- geek_cafe_saas_sdk/domains/files/models/directory.py +258 -0
- geek_cafe_saas_sdk/domains/files/models/file.py +312 -0
- geek_cafe_saas_sdk/domains/files/models/file_share.py +268 -0
- geek_cafe_saas_sdk/domains/files/models/file_version.py +216 -0
- geek_cafe_saas_sdk/domains/files/services/__init__.py +0 -0
- geek_cafe_saas_sdk/domains/files/services/directory_service.py +701 -0
- geek_cafe_saas_sdk/domains/files/services/file_share_service.py +663 -0
- geek_cafe_saas_sdk/domains/files/services/file_system_service.py +575 -0
- geek_cafe_saas_sdk/domains/files/services/file_version_service.py +739 -0
- geek_cafe_saas_sdk/domains/files/services/s3_file_service.py +501 -0
- geek_cafe_saas_sdk/domains/messaging/__init__.py +0 -0
- geek_cafe_saas_sdk/domains/messaging/handlers/__init__.py +0 -0
- geek_cafe_saas_sdk/domains/messaging/handlers/chat_channels/create/app.py +86 -0
- geek_cafe_saas_sdk/domains/messaging/handlers/chat_channels/delete/app.py +65 -0
- geek_cafe_saas_sdk/domains/messaging/handlers/chat_channels/get/app.py +64 -0
- geek_cafe_saas_sdk/domains/messaging/handlers/chat_channels/list/app.py +97 -0
- geek_cafe_saas_sdk/domains/messaging/handlers/chat_channels/update/app.py +149 -0
- geek_cafe_saas_sdk/domains/messaging/handlers/chat_messages/create/app.py +67 -0
- geek_cafe_saas_sdk/domains/messaging/handlers/chat_messages/delete/app.py +65 -0
- geek_cafe_saas_sdk/domains/messaging/handlers/chat_messages/get/app.py +64 -0
- geek_cafe_saas_sdk/domains/messaging/handlers/chat_messages/list/app.py +102 -0
- geek_cafe_saas_sdk/domains/messaging/handlers/chat_messages/update/app.py +127 -0
- geek_cafe_saas_sdk/domains/messaging/handlers/contact_threads/create/app.py +94 -0
- geek_cafe_saas_sdk/domains/messaging/handlers/contact_threads/delete/app.py +66 -0
- geek_cafe_saas_sdk/domains/messaging/handlers/contact_threads/get/app.py +67 -0
- geek_cafe_saas_sdk/domains/messaging/handlers/contact_threads/list/app.py +95 -0
- geek_cafe_saas_sdk/domains/messaging/handlers/contact_threads/update/app.py +156 -0
- geek_cafe_saas_sdk/domains/messaging/models/__init__.py +13 -0
- geek_cafe_saas_sdk/domains/messaging/models/chat_channel.py +337 -0
- geek_cafe_saas_sdk/domains/messaging/models/chat_channel_member.py +180 -0
- geek_cafe_saas_sdk/domains/messaging/models/chat_message.py +426 -0
- geek_cafe_saas_sdk/domains/messaging/models/contact_thread.py +392 -0
- geek_cafe_saas_sdk/domains/messaging/services/__init__.py +11 -0
- geek_cafe_saas_sdk/domains/messaging/services/chat_channel_service.py +700 -0
- geek_cafe_saas_sdk/domains/messaging/services/chat_message_service.py +491 -0
- geek_cafe_saas_sdk/domains/messaging/services/contact_thread_service.py +497 -0
- geek_cafe_saas_sdk/domains/tenancy/__init__.py +0 -0
- geek_cafe_saas_sdk/domains/tenancy/handlers/__init__.py +0 -0
- geek_cafe_saas_sdk/domains/tenancy/handlers/subscriptions/activate/app.py +52 -0
- geek_cafe_saas_sdk/domains/tenancy/handlers/subscriptions/active/app.py +37 -0
- geek_cafe_saas_sdk/domains/tenancy/handlers/subscriptions/cancel/app.py +55 -0
- geek_cafe_saas_sdk/domains/tenancy/handlers/subscriptions/get/app.py +39 -0
- geek_cafe_saas_sdk/domains/tenancy/handlers/subscriptions/list/app.py +44 -0
- geek_cafe_saas_sdk/domains/tenancy/handlers/subscriptions/record_payment/app.py +56 -0
- geek_cafe_saas_sdk/domains/tenancy/handlers/tenants/get/app.py +39 -0
- geek_cafe_saas_sdk/domains/tenancy/handlers/tenants/me/app.py +37 -0
- geek_cafe_saas_sdk/domains/tenancy/handlers/tenants/signup/app.py +61 -0
- geek_cafe_saas_sdk/domains/tenancy/handlers/tenants/update/app.py +44 -0
- geek_cafe_saas_sdk/domains/tenancy/models/__init__.py +6 -0
- geek_cafe_saas_sdk/domains/tenancy/models/subscription.py +440 -0
- geek_cafe_saas_sdk/domains/tenancy/models/tenant.py +258 -0
- geek_cafe_saas_sdk/domains/tenancy/services/__init__.py +6 -0
- geek_cafe_saas_sdk/domains/tenancy/services/subscription_service.py +557 -0
- geek_cafe_saas_sdk/domains/tenancy/services/tenant_service.py +575 -0
- geek_cafe_saas_sdk/domains/voting/__init__.py +0 -0
- geek_cafe_saas_sdk/domains/voting/handlers/__init__.py +0 -0
- geek_cafe_saas_sdk/domains/voting/handlers/votes/create/app.py +128 -0
- geek_cafe_saas_sdk/domains/voting/handlers/votes/delete/app.py +41 -0
- geek_cafe_saas_sdk/domains/voting/handlers/votes/get/app.py +39 -0
- geek_cafe_saas_sdk/domains/voting/handlers/votes/list/app.py +38 -0
- geek_cafe_saas_sdk/domains/voting/handlers/votes/summerize/README.md +3 -0
- geek_cafe_saas_sdk/domains/voting/handlers/votes/update/app.py +44 -0
- geek_cafe_saas_sdk/domains/voting/models/__init__.py +9 -0
- geek_cafe_saas_sdk/domains/voting/models/vote.py +231 -0
- geek_cafe_saas_sdk/domains/voting/models/vote_summary.py +193 -0
- geek_cafe_saas_sdk/domains/voting/services/__init__.py +11 -0
- geek_cafe_saas_sdk/domains/voting/services/vote_service.py +264 -0
- geek_cafe_saas_sdk/domains/voting/services/vote_summary_service.py +198 -0
- geek_cafe_saas_sdk/domains/voting/services/vote_tally_service.py +533 -0
- geek_cafe_saas_sdk/lambda_handlers/README.md +404 -0
- geek_cafe_saas_sdk/lambda_handlers/__init__.py +67 -0
- geek_cafe_saas_sdk/lambda_handlers/_base/__init__.py +25 -0
- geek_cafe_saas_sdk/lambda_handlers/_base/api_key_handler.py +129 -0
- geek_cafe_saas_sdk/lambda_handlers/_base/authorized_secure_handler.py +218 -0
- geek_cafe_saas_sdk/lambda_handlers/_base/base_handler.py +185 -0
- geek_cafe_saas_sdk/lambda_handlers/_base/handler_factory.py +256 -0
- geek_cafe_saas_sdk/lambda_handlers/_base/public_handler.py +53 -0
- geek_cafe_saas_sdk/lambda_handlers/_base/secure_handler.py +89 -0
- geek_cafe_saas_sdk/lambda_handlers/_base/service_pool.py +94 -0
- geek_cafe_saas_sdk/lambda_handlers/directories/create/app.py +79 -0
- geek_cafe_saas_sdk/lambda_handlers/directories/delete/app.py +76 -0
- geek_cafe_saas_sdk/lambda_handlers/directories/get/app.py +74 -0
- geek_cafe_saas_sdk/lambda_handlers/directories/list/app.py +75 -0
- geek_cafe_saas_sdk/lambda_handlers/directories/move/app.py +79 -0
- geek_cafe_saas_sdk/lambda_handlers/files/delete/app.py +121 -0
- geek_cafe_saas_sdk/lambda_handlers/files/download/app.py +187 -0
- geek_cafe_saas_sdk/lambda_handlers/files/get/app.py +127 -0
- geek_cafe_saas_sdk/lambda_handlers/files/list/app.py +108 -0
- geek_cafe_saas_sdk/lambda_handlers/files/share/app.py +83 -0
- geek_cafe_saas_sdk/lambda_handlers/files/shares/list/app.py +84 -0
- geek_cafe_saas_sdk/lambda_handlers/files/shares/revoke/app.py +76 -0
- geek_cafe_saas_sdk/lambda_handlers/files/update/app.py +143 -0
- geek_cafe_saas_sdk/lambda_handlers/files/upload/app.py +151 -0
- geek_cafe_saas_sdk/middleware/__init__.py +36 -0
- geek_cafe_saas_sdk/middleware/auth.py +85 -0
- geek_cafe_saas_sdk/middleware/authorization.py +523 -0
- geek_cafe_saas_sdk/middleware/cors.py +63 -0
- geek_cafe_saas_sdk/middleware/error_handling.py +114 -0
- geek_cafe_saas_sdk/middleware/validation.py +80 -0
- geek_cafe_saas_sdk/models/__init__.py +20 -0
- geek_cafe_saas_sdk/models/base_model.py +233 -0
- geek_cafe_saas_sdk/services/__init__.py +18 -0
- geek_cafe_saas_sdk/services/database_service.py +441 -0
- geek_cafe_saas_sdk/utilities/__init__.py +88 -0
- geek_cafe_saas_sdk/utilities/cognito_utility.py +568 -0
- geek_cafe_saas_sdk/utilities/custom_exceptions.py +183 -0
- geek_cafe_saas_sdk/utilities/datetime_utility.py +410 -0
- geek_cafe_saas_sdk/utilities/dictionary_utility.py +78 -0
- geek_cafe_saas_sdk/utilities/dynamodb_utils.py +151 -0
- geek_cafe_saas_sdk/utilities/environment_loader.py +149 -0
- geek_cafe_saas_sdk/utilities/environment_variables.py +228 -0
- geek_cafe_saas_sdk/utilities/http_body_parameters.py +44 -0
- geek_cafe_saas_sdk/utilities/http_path_parameters.py +60 -0
- geek_cafe_saas_sdk/utilities/http_status_code.py +63 -0
- geek_cafe_saas_sdk/utilities/jwt_utility.py +234 -0
- geek_cafe_saas_sdk/utilities/lambda_event_utility.py +776 -0
- geek_cafe_saas_sdk/utilities/logging_utility.py +64 -0
- geek_cafe_saas_sdk/utilities/message_query_helper.py +340 -0
- geek_cafe_saas_sdk/utilities/response.py +209 -0
- geek_cafe_saas_sdk/utilities/string_functions.py +180 -0
- geek_cafe_saas_sdk-0.6.0.dist-info/METADATA +397 -0
- geek_cafe_saas_sdk-0.6.0.dist-info/RECORD +194 -0
- geek_cafe_saas_sdk-0.6.0.dist-info/WHEEL +4 -0
- 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
|
+
)
|