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,93 @@
|
|
|
1
|
+
# src/geek_cafe_saas_sdk/lambda_handlers/events/create/app.py
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from typing import Dict, Any
|
|
5
|
+
|
|
6
|
+
from geek_cafe_saas_sdk.domains.events.services.event_service import EventService
|
|
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
|
+
from geek_cafe_saas_sdk.domains.events.models.event import Event
|
|
11
|
+
|
|
12
|
+
event_service_pool = ServicePool(EventService)
|
|
13
|
+
|
|
14
|
+
def handler(event: Dict[str, Any], context: object, injected_service=None) -> Dict[str, Any]:
|
|
15
|
+
"""
|
|
16
|
+
Lambda handler for creating a new event.
|
|
17
|
+
|
|
18
|
+
Supports both timestamp-based and ISO8601 datetime formats.
|
|
19
|
+
Automatically creates EventAttendee record for owner as organizer.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
event: API Gateway event
|
|
23
|
+
context: Lambda context
|
|
24
|
+
injected_service: Optional EventService for testing (Moto)
|
|
25
|
+
|
|
26
|
+
Expected body (all optional except title and start time):
|
|
27
|
+
{
|
|
28
|
+
"title": "Python Meetup",
|
|
29
|
+
"start_utc_ts": 1731717600.0, // OR use start_datetime
|
|
30
|
+
"start_datetime": "2025-11-15T18:00:00-08:00", // Auto-converts to timestamp
|
|
31
|
+
"end_utc_ts": 1731728400.0, // OR use end_datetime
|
|
32
|
+
"end_datetime": "2025-11-15T21:00:00-08:00",
|
|
33
|
+
"timezone": "America/Los_Angeles",
|
|
34
|
+
"description": "Monthly Python meetup",
|
|
35
|
+
"event_type": "meetup",
|
|
36
|
+
"status": "draft", // or "published"
|
|
37
|
+
"visibility": "public",
|
|
38
|
+
|
|
39
|
+
// Location
|
|
40
|
+
"location_type": "physical", // physical, virtual, hybrid
|
|
41
|
+
"location_name": "Tech Hub SF",
|
|
42
|
+
"location_address": "123 Main St",
|
|
43
|
+
"location_city": "San Francisco",
|
|
44
|
+
"location_state": "CA",
|
|
45
|
+
"location_country": "US",
|
|
46
|
+
"location_latitude": 37.7749,
|
|
47
|
+
"location_longitude": -122.4194,
|
|
48
|
+
"virtual_link": "https://zoom.us/...",
|
|
49
|
+
|
|
50
|
+
// Capacity
|
|
51
|
+
"max_attendees": 50,
|
|
52
|
+
"allow_waitlist": true,
|
|
53
|
+
"requires_approval": false,
|
|
54
|
+
"allow_guest_plus_one": true,
|
|
55
|
+
"registration_deadline_utc_ts": 1731600000.0,
|
|
56
|
+
|
|
57
|
+
// Other
|
|
58
|
+
"group_id": "group_123",
|
|
59
|
+
"tags": ["python", "networking"],
|
|
60
|
+
"custom_fields": {"dietary": "text", "experience": "select"}
|
|
61
|
+
}
|
|
62
|
+
"""
|
|
63
|
+
try:
|
|
64
|
+
# Use injected service (testing) or pool (production)
|
|
65
|
+
event_service = injected_service if injected_service else event_service_pool.get()
|
|
66
|
+
body = LambdaEventUtility.get_body_from_event(event)
|
|
67
|
+
user_id = LambdaEventUtility.get_authenticated_user_id(event)
|
|
68
|
+
tenant_id = LambdaEventUtility.get_authenticated_user_tenant_id(event)
|
|
69
|
+
|
|
70
|
+
# Convert ISO8601 datetime strings to timestamps if provided
|
|
71
|
+
if 'start_datetime' in body and 'start_utc_ts' not in body:
|
|
72
|
+
body['start_utc_ts'] = Event.datetime_to_utc_ts(body['start_datetime'])
|
|
73
|
+
if 'end_datetime' in body and 'end_utc_ts' not in body:
|
|
74
|
+
body['end_utc_ts'] = Event.datetime_to_utc_ts(body['end_datetime'])
|
|
75
|
+
if 'registration_deadline_datetime' in body and 'registration_deadline_utc_ts' not in body:
|
|
76
|
+
body['registration_deadline_utc_ts'] = Event.datetime_to_utc_ts(body['registration_deadline_datetime'])
|
|
77
|
+
|
|
78
|
+
# Pass all body parameters to the service
|
|
79
|
+
# Service will auto-create EventAttendee for owner
|
|
80
|
+
result = event_service.create(
|
|
81
|
+
tenant_id=tenant_id,
|
|
82
|
+
user_id=user_id,
|
|
83
|
+
create_organizer_attendee=True, # Auto-create attendee record
|
|
84
|
+
**body
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
return service_result_to_response(result, success_status=201)
|
|
88
|
+
|
|
89
|
+
except json.JSONDecodeError:
|
|
90
|
+
return error_response("Invalid JSON format in request body.", "VALIDATION_ERROR", 400)
|
|
91
|
+
except Exception as e:
|
|
92
|
+
# In a production environment, log the exception e
|
|
93
|
+
return error_response(f"An unexpected error occurred: {str(e)}", "INTERNAL_ERROR", 500)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# src/geek_cafe_saas_sdk/lambda_handlers/events/delete/app.py
|
|
2
|
+
|
|
3
|
+
from typing import Dict, Any
|
|
4
|
+
|
|
5
|
+
from geek_cafe_saas_sdk.domains.events.services.event_service import EventService
|
|
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, success_response
|
|
8
|
+
from geek_cafe_saas_sdk.utilities.lambda_event_utility import LambdaEventUtility
|
|
9
|
+
|
|
10
|
+
event_service_pool = ServicePool(EventService)
|
|
11
|
+
|
|
12
|
+
def handler(event: Dict[str, Any], context: object, injected_service=None) -> Dict[str, Any]:
|
|
13
|
+
"""
|
|
14
|
+
Lambda handler for deleting an event by its ID.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
event: API Gateway event
|
|
18
|
+
context: Lambda context
|
|
19
|
+
injected_service: Optional EventService for testing
|
|
20
|
+
"""
|
|
21
|
+
try:
|
|
22
|
+
event_service = injected_service if injected_service else event_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("Event ID is required in the path.", "VALIDATION_ERROR", 400)
|
|
29
|
+
|
|
30
|
+
result = event_service.delete(
|
|
31
|
+
resource_id=resource_id,
|
|
32
|
+
tenant_id=tenant_id,
|
|
33
|
+
user_id=user_id
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
if result.success:
|
|
37
|
+
return success_response(None, status_code=204)
|
|
38
|
+
else:
|
|
39
|
+
return service_result_to_response(result)
|
|
40
|
+
|
|
41
|
+
except Exception as e:
|
|
42
|
+
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/events/get/app.py
|
|
2
|
+
|
|
3
|
+
from typing import Dict, Any
|
|
4
|
+
|
|
5
|
+
from geek_cafe_saas_sdk.domains.events.services.event_service import EventService
|
|
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
|
+
event_service_pool = ServicePool(EventService)
|
|
11
|
+
|
|
12
|
+
def handler(event: Dict[str, Any], context: object, injected_service=None) -> Dict[str, Any]:
|
|
13
|
+
"""
|
|
14
|
+
Lambda handler for retrieving a single event by its ID.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
event: API Gateway event
|
|
18
|
+
context: Lambda context
|
|
19
|
+
injected_service: Optional EventService for testing
|
|
20
|
+
"""
|
|
21
|
+
try:
|
|
22
|
+
event_service = injected_service if injected_service else event_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("Event ID is required in the path.", "VALIDATION_ERROR", 400)
|
|
29
|
+
|
|
30
|
+
result = event_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,98 @@
|
|
|
1
|
+
# src/geek_cafe_saas_sdk/lambda_handlers/events/invite/app.py
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from typing import Dict, Any
|
|
5
|
+
|
|
6
|
+
from geek_cafe_saas_sdk.domains.events.services.event_attendee_service import EventAttendeeService
|
|
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
|
+
attendee_service_pool = ServicePool(EventAttendeeService)
|
|
12
|
+
|
|
13
|
+
def handler(event: Dict[str, Any], context: object, injected_service=None) -> Dict[str, Any]:
|
|
14
|
+
"""
|
|
15
|
+
Lambda handler for inviting user(s) to an event.
|
|
16
|
+
|
|
17
|
+
Supports single and bulk invitations.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
event: API Gateway event
|
|
21
|
+
context: Lambda context
|
|
22
|
+
injected_service: Optional EventAttendeeService for testing
|
|
23
|
+
|
|
24
|
+
Expected body:
|
|
25
|
+
{
|
|
26
|
+
"event_id": "evt_123",
|
|
27
|
+
"user_id": "user_456", // For single invite
|
|
28
|
+
"user_ids": ["user_1", "user_2"], // For bulk invite
|
|
29
|
+
"role": "attendee", // or "co_host", "speaker", "volunteer"
|
|
30
|
+
"registration_data": {"dietary": "vegetarian"},
|
|
31
|
+
"registration_notes": "Looking forward to it!"
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
Returns 201 with invitation record(s)
|
|
35
|
+
"""
|
|
36
|
+
try:
|
|
37
|
+
attendee_service = injected_service if injected_service else attendee_service_pool.get()
|
|
38
|
+
body = LambdaEventUtility.get_body_from_event(event)
|
|
39
|
+
user_id = LambdaEventUtility.get_authenticated_user_id(event)
|
|
40
|
+
tenant_id = LambdaEventUtility.get_authenticated_user_tenant_id(event)
|
|
41
|
+
|
|
42
|
+
# Validate required fields
|
|
43
|
+
event_id = body.get('event_id')
|
|
44
|
+
if not event_id:
|
|
45
|
+
return error_response("event_id is required", "VALIDATION_ERROR", 400)
|
|
46
|
+
|
|
47
|
+
# Check for bulk invite
|
|
48
|
+
if 'user_ids' in body:
|
|
49
|
+
# Bulk invite
|
|
50
|
+
user_ids = body.get('user_ids', [])
|
|
51
|
+
if not user_ids:
|
|
52
|
+
return error_response("user_ids must be a non-empty list", "VALIDATION_ERROR", 400)
|
|
53
|
+
|
|
54
|
+
# Extract optional params
|
|
55
|
+
kwargs = {}
|
|
56
|
+
if 'role' in body:
|
|
57
|
+
kwargs['role'] = body['role']
|
|
58
|
+
if 'registration_data' in body:
|
|
59
|
+
kwargs['registration_data'] = body['registration_data']
|
|
60
|
+
if 'registration_notes' in body:
|
|
61
|
+
kwargs['registration_notes'] = body['registration_notes']
|
|
62
|
+
|
|
63
|
+
result = attendee_service.bulk_invite(
|
|
64
|
+
event_id=event_id,
|
|
65
|
+
user_ids=user_ids,
|
|
66
|
+
tenant_id=tenant_id,
|
|
67
|
+
invited_by_user_id=user_id,
|
|
68
|
+
**kwargs
|
|
69
|
+
)
|
|
70
|
+
else:
|
|
71
|
+
# Single invite
|
|
72
|
+
invitee_user_id = body.get('user_id')
|
|
73
|
+
if not invitee_user_id:
|
|
74
|
+
return error_response("user_id or user_ids is required", "VALIDATION_ERROR", 400)
|
|
75
|
+
|
|
76
|
+
# Extract optional params
|
|
77
|
+
kwargs = {}
|
|
78
|
+
if 'role' in body:
|
|
79
|
+
kwargs['role'] = body['role']
|
|
80
|
+
if 'registration_data' in body:
|
|
81
|
+
kwargs['registration_data'] = body['registration_data']
|
|
82
|
+
if 'registration_notes' in body:
|
|
83
|
+
kwargs['registration_notes'] = body['registration_notes']
|
|
84
|
+
|
|
85
|
+
result = attendee_service.invite(
|
|
86
|
+
event_id=event_id,
|
|
87
|
+
user_id=invitee_user_id,
|
|
88
|
+
tenant_id=tenant_id,
|
|
89
|
+
invited_by_user_id=user_id,
|
|
90
|
+
**kwargs
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
return service_result_to_response(result, success_status=201)
|
|
94
|
+
|
|
95
|
+
except json.JSONDecodeError:
|
|
96
|
+
return error_response("Invalid JSON format in request body.", "VALIDATION_ERROR", 400)
|
|
97
|
+
except Exception as e:
|
|
98
|
+
return error_response(f"An unexpected error occurred: {str(e)}", "INTERNAL_ERROR", 500)
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# src/geek_cafe_saas_sdk/lambda_handlers/events/list/app.py
|
|
2
|
+
|
|
3
|
+
from typing import Dict, Any
|
|
4
|
+
|
|
5
|
+
from geek_cafe_saas_sdk.domains.events.services.event_service import EventService
|
|
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
|
+
event_service_pool = ServicePool(EventService)
|
|
11
|
+
|
|
12
|
+
def handler(event: Dict[str, Any], context: object, injected_service=None) -> Dict[str, Any]:
|
|
13
|
+
"""
|
|
14
|
+
Lambda handler for listing events with location-based and other filters.
|
|
15
|
+
|
|
16
|
+
Supports multiple query patterns:
|
|
17
|
+
- By city: ?city=San Francisco&state=CA&country=US
|
|
18
|
+
- By state: ?state=CA&country=US
|
|
19
|
+
- Nearby: ?latitude=37.7749&longitude=-122.4194&radius=25
|
|
20
|
+
- By owner: ?owner_id=user_123
|
|
21
|
+
- By type: ?event_type=meetup&status=published
|
|
22
|
+
- By group: ?group_id=group_123
|
|
23
|
+
- Public discovery: ?visibility=public&status=published
|
|
24
|
+
- All for tenant: (no params)
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
event: API Gateway event
|
|
28
|
+
context: Lambda context
|
|
29
|
+
injected_service: Optional EventService for testing
|
|
30
|
+
|
|
31
|
+
Query Parameters:
|
|
32
|
+
city: City name
|
|
33
|
+
state: State/Province/Region
|
|
34
|
+
country: Country code
|
|
35
|
+
latitude: Latitude for nearby search
|
|
36
|
+
longitude: Longitude for nearby search
|
|
37
|
+
radius: Radius in km (default 25)
|
|
38
|
+
owner_id: Owner user ID
|
|
39
|
+
event_type: Event type (meetup, conference, etc.)
|
|
40
|
+
group_id: Group ID
|
|
41
|
+
visibility: public, private, members_only
|
|
42
|
+
status: draft, published, cancelled, completed
|
|
43
|
+
limit: Max results (default 50)
|
|
44
|
+
"""
|
|
45
|
+
try:
|
|
46
|
+
event_service = injected_service if injected_service else event_service_pool.get()
|
|
47
|
+
user_id = LambdaEventUtility.get_authenticated_user_id(event)
|
|
48
|
+
tenant_id = LambdaEventUtility.get_authenticated_user_tenant_id(event)
|
|
49
|
+
query_params = event.get('queryStringParameters', {}) or {}
|
|
50
|
+
|
|
51
|
+
# Extract common parameters
|
|
52
|
+
limit = int(query_params.get('limit', 50))
|
|
53
|
+
|
|
54
|
+
# Route to appropriate service method based on query params
|
|
55
|
+
if 'latitude' in query_params and 'longitude' in query_params:
|
|
56
|
+
# Nearby search (geo-location)
|
|
57
|
+
result = event_service.list_nearby(
|
|
58
|
+
latitude=float(query_params['latitude']),
|
|
59
|
+
longitude=float(query_params['longitude']),
|
|
60
|
+
radius_km=float(query_params.get('radius', 25)),
|
|
61
|
+
tenant_id=tenant_id,
|
|
62
|
+
limit=limit
|
|
63
|
+
)
|
|
64
|
+
elif 'city' in query_params:
|
|
65
|
+
# City search
|
|
66
|
+
result = event_service.list_by_city(
|
|
67
|
+
city=query_params['city'],
|
|
68
|
+
state=query_params.get('state'),
|
|
69
|
+
country=query_params.get('country'),
|
|
70
|
+
tenant_id=tenant_id,
|
|
71
|
+
limit=limit
|
|
72
|
+
)
|
|
73
|
+
elif 'state' in query_params:
|
|
74
|
+
# State/region search
|
|
75
|
+
result = event_service.list_by_state(
|
|
76
|
+
state=query_params['state'],
|
|
77
|
+
country=query_params.get('country'),
|
|
78
|
+
tenant_id=tenant_id,
|
|
79
|
+
limit=limit
|
|
80
|
+
)
|
|
81
|
+
elif 'owner_id' in query_params:
|
|
82
|
+
# Events by owner
|
|
83
|
+
result = event_service.list_by_owner(
|
|
84
|
+
owner_id=query_params['owner_id'],
|
|
85
|
+
tenant_id=tenant_id,
|
|
86
|
+
limit=limit
|
|
87
|
+
)
|
|
88
|
+
elif 'event_type' in query_params:
|
|
89
|
+
# Events by type
|
|
90
|
+
status = query_params.get('status', 'published')
|
|
91
|
+
result = event_service.list_by_type(
|
|
92
|
+
event_type=query_params['event_type'],
|
|
93
|
+
tenant_id=tenant_id,
|
|
94
|
+
status=status,
|
|
95
|
+
limit=limit
|
|
96
|
+
)
|
|
97
|
+
elif 'group_id' in query_params:
|
|
98
|
+
# Events by group
|
|
99
|
+
result = event_service.list_by_group(
|
|
100
|
+
group_id=query_params['group_id'],
|
|
101
|
+
tenant_id=tenant_id,
|
|
102
|
+
limit=limit
|
|
103
|
+
)
|
|
104
|
+
elif 'visibility' in query_params:
|
|
105
|
+
# Public discovery
|
|
106
|
+
status = query_params.get('status', 'published')
|
|
107
|
+
result = event_service.list_public_events(
|
|
108
|
+
tenant_id=tenant_id,
|
|
109
|
+
visibility=query_params['visibility'],
|
|
110
|
+
status=status,
|
|
111
|
+
limit=limit
|
|
112
|
+
)
|
|
113
|
+
else:
|
|
114
|
+
# All events for tenant
|
|
115
|
+
result = event_service.list_by_tenant(
|
|
116
|
+
tenant_id=tenant_id,
|
|
117
|
+
limit=limit
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
return service_result_to_response(result)
|
|
121
|
+
|
|
122
|
+
except ValueError as e:
|
|
123
|
+
return error_response(f"Invalid parameter value: {str(e)}", "VALIDATION_ERROR", 400)
|
|
124
|
+
except Exception as e:
|
|
125
|
+
return error_response(f"An unexpected error occurred: {str(e)}", "INTERNAL_ERROR", 500)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# src/geek_cafe_saas_sdk/lambda_handlers/events/publish/app.py
|
|
2
|
+
|
|
3
|
+
from typing import Dict, Any
|
|
4
|
+
|
|
5
|
+
from geek_cafe_saas_sdk.domains.events.services.event_service import EventService
|
|
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
|
+
event_service_pool = ServicePool(EventService)
|
|
11
|
+
|
|
12
|
+
def handler(event: Dict[str, Any], context: object, injected_service=None) -> Dict[str, Any]:
|
|
13
|
+
"""
|
|
14
|
+
Lambda handler for publishing a draft event.
|
|
15
|
+
|
|
16
|
+
Changes status from 'draft' to 'published'.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
event: API Gateway event
|
|
20
|
+
context: Lambda context
|
|
21
|
+
injected_service: Optional EventService for testing
|
|
22
|
+
|
|
23
|
+
Path Parameters:
|
|
24
|
+
id: Event ID
|
|
25
|
+
|
|
26
|
+
Example:
|
|
27
|
+
POST /events/{id}/publish
|
|
28
|
+
|
|
29
|
+
Returns 200 with published event
|
|
30
|
+
"""
|
|
31
|
+
try:
|
|
32
|
+
event_service = injected_service if injected_service else event_service_pool.get()
|
|
33
|
+
user_id = LambdaEventUtility.get_authenticated_user_id(event)
|
|
34
|
+
tenant_id = LambdaEventUtility.get_authenticated_user_tenant_id(event)
|
|
35
|
+
resource_id = LambdaEventUtility.get_value_from_path_parameters(event, 'id')
|
|
36
|
+
|
|
37
|
+
if not resource_id:
|
|
38
|
+
return error_response("Event ID is required in the path.", "VALIDATION_ERROR", 400)
|
|
39
|
+
|
|
40
|
+
result = event_service.publish(
|
|
41
|
+
resource_id=resource_id,
|
|
42
|
+
tenant_id=tenant_id,
|
|
43
|
+
user_id=user_id
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
return service_result_to_response(result)
|
|
47
|
+
|
|
48
|
+
except Exception as e:
|
|
49
|
+
return error_response(f"An unexpected error occurred: {str(e)}", "INTERNAL_ERROR", 500)
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# src/geek_cafe_saas_sdk/lambda_handlers/events/rsvp/app.py
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from typing import Dict, Any
|
|
5
|
+
|
|
6
|
+
from geek_cafe_saas_sdk.domains.events.services.event_attendee_service import EventAttendeeService
|
|
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
|
+
attendee_service_pool = ServicePool(EventAttendeeService)
|
|
12
|
+
|
|
13
|
+
def handler(event: Dict[str, Any], context: object, injected_service=None) -> Dict[str, Any]:
|
|
14
|
+
"""
|
|
15
|
+
Lambda handler for updating RSVP status.
|
|
16
|
+
|
|
17
|
+
Allows users to accept, decline, or mark as tentative.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
event: API Gateway event
|
|
21
|
+
context: Lambda context
|
|
22
|
+
injected_service: Optional EventAttendeeService for testing
|
|
23
|
+
|
|
24
|
+
Expected body:
|
|
25
|
+
{
|
|
26
|
+
"event_id": "evt_123",
|
|
27
|
+
"rsvp_status": "accepted", // accepted, declined, tentative
|
|
28
|
+
"plus_one_count": 1, // Optional
|
|
29
|
+
"plus_one_names": ["Jane Doe"], // Optional
|
|
30
|
+
"registration_data": {"dietary": "vegetarian", "experience": "beginner"}, // Optional
|
|
31
|
+
"registration_notes": "Excited to attend!" // Optional
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
Returns 200 with updated attendee record
|
|
35
|
+
"""
|
|
36
|
+
try:
|
|
37
|
+
attendee_service = injected_service if injected_service else attendee_service_pool.get()
|
|
38
|
+
body = LambdaEventUtility.get_body_from_event(event)
|
|
39
|
+
user_id = LambdaEventUtility.get_authenticated_user_id(event)
|
|
40
|
+
tenant_id = LambdaEventUtility.get_authenticated_user_tenant_id(event)
|
|
41
|
+
|
|
42
|
+
# Validate required fields
|
|
43
|
+
event_id = body.get('event_id')
|
|
44
|
+
rsvp_status = body.get('rsvp_status')
|
|
45
|
+
|
|
46
|
+
if not event_id:
|
|
47
|
+
return error_response("event_id is required", "VALIDATION_ERROR", 400)
|
|
48
|
+
if not rsvp_status:
|
|
49
|
+
return error_response("rsvp_status is required", "VALIDATION_ERROR", 400)
|
|
50
|
+
if rsvp_status not in ['accepted', 'declined', 'tentative']:
|
|
51
|
+
return error_response(
|
|
52
|
+
"rsvp_status must be one of: accepted, declined, tentative",
|
|
53
|
+
"VALIDATION_ERROR",
|
|
54
|
+
400
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
# Extract optional params
|
|
58
|
+
kwargs = {}
|
|
59
|
+
if 'plus_one_count' in body:
|
|
60
|
+
kwargs['plus_one_count'] = int(body['plus_one_count'])
|
|
61
|
+
if 'plus_one_names' in body:
|
|
62
|
+
kwargs['plus_one_names'] = body['plus_one_names']
|
|
63
|
+
if 'registration_data' in body:
|
|
64
|
+
kwargs['registration_data'] = body['registration_data']
|
|
65
|
+
if 'registration_notes' in body:
|
|
66
|
+
kwargs['registration_notes'] = body['registration_notes']
|
|
67
|
+
|
|
68
|
+
result = attendee_service.update_rsvp(
|
|
69
|
+
event_id=event_id,
|
|
70
|
+
user_id=user_id,
|
|
71
|
+
tenant_id=tenant_id,
|
|
72
|
+
rsvp_status=rsvp_status,
|
|
73
|
+
**kwargs
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
return service_result_to_response(result)
|
|
77
|
+
|
|
78
|
+
except json.JSONDecodeError:
|
|
79
|
+
return error_response("Invalid JSON format in request body.", "VALIDATION_ERROR", 400)
|
|
80
|
+
except ValueError as e:
|
|
81
|
+
return error_response(f"Invalid parameter value: {str(e)}", "VALIDATION_ERROR", 400)
|
|
82
|
+
except Exception as e:
|
|
83
|
+
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/events/update/app.py
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from typing import Dict, Any
|
|
5
|
+
|
|
6
|
+
from geek_cafe_saas_sdk.domains.events.services.event_service import EventService
|
|
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
|
+
event_service_pool = ServicePool(EventService)
|
|
12
|
+
|
|
13
|
+
def handler(event: Dict[str, Any], context: object, injected_service=None) -> Dict[str, Any]:
|
|
14
|
+
"""
|
|
15
|
+
Lambda handler for updating an existing event.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
event: API Gateway event
|
|
19
|
+
context: Lambda context
|
|
20
|
+
injected_service: Optional EventService for testing
|
|
21
|
+
"""
|
|
22
|
+
try:
|
|
23
|
+
event_service = injected_service if injected_service else event_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("Event ID is required in the path.", "VALIDATION_ERROR", 400)
|
|
31
|
+
|
|
32
|
+
result = event_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 format 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)
|