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,121 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Lambda handler for deleting files.
|
|
3
|
+
|
|
4
|
+
Geek Cafe, LLC
|
|
5
|
+
MIT License. See Project Root for the license information.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
from typing import Dict, Any
|
|
11
|
+
|
|
12
|
+
from boto3_assist.dynamodb.dynamodb import DynamoDB
|
|
13
|
+
from boto3_assist.s3.s3_connection import S3Connection
|
|
14
|
+
from boto3_assist.s3.s3_object import S3Object
|
|
15
|
+
from boto3_assist.s3.s3_bucket import S3Bucket
|
|
16
|
+
|
|
17
|
+
from geek_cafe_saas_sdk.domains.files.services.file_system_service import FileSystemService
|
|
18
|
+
from geek_cafe_saas_sdk.domains.files.services.s3_file_service import S3FileService
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, Any]:
|
|
22
|
+
"""
|
|
23
|
+
Delete file handler.
|
|
24
|
+
|
|
25
|
+
Expected Event:
|
|
26
|
+
{
|
|
27
|
+
"pathParameters": {
|
|
28
|
+
"file_id": "file-123"
|
|
29
|
+
},
|
|
30
|
+
"queryStringParameters": {
|
|
31
|
+
"tenant_id": "tenant-456",
|
|
32
|
+
"user_id": "user-789",
|
|
33
|
+
"hard_delete": "false" # Optional, default false
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
{
|
|
39
|
+
"statusCode": 200,
|
|
40
|
+
"body": {
|
|
41
|
+
"success": true,
|
|
42
|
+
"message": "File deleted successfully"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
"""
|
|
46
|
+
try:
|
|
47
|
+
# Extract parameters
|
|
48
|
+
path_params = event.get('pathParameters', {})
|
|
49
|
+
query_params = event.get('queryStringParameters', {})
|
|
50
|
+
|
|
51
|
+
file_id = path_params.get('file_id')
|
|
52
|
+
tenant_id = query_params.get('tenant_id')
|
|
53
|
+
user_id = query_params.get('user_id')
|
|
54
|
+
hard_delete = query_params.get('hard_delete', 'false').lower() == 'true'
|
|
55
|
+
|
|
56
|
+
# Validate required fields
|
|
57
|
+
if not all([file_id, tenant_id, user_id]):
|
|
58
|
+
return {
|
|
59
|
+
'statusCode': 400,
|
|
60
|
+
'body': json.dumps({
|
|
61
|
+
'success': False,
|
|
62
|
+
'message': 'Missing required parameters: file_id, tenant_id, user_id'
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
# Initialize services
|
|
67
|
+
table_name = os.environ.get('DYNAMODB_TABLE_NAME', 'files-table')
|
|
68
|
+
bucket_name = os.environ.get('S3_BUCKET_NAME', 'files-bucket')
|
|
69
|
+
|
|
70
|
+
db = DynamoDB()
|
|
71
|
+
connection = S3Connection()
|
|
72
|
+
|
|
73
|
+
s3_service = S3FileService(
|
|
74
|
+
s3_object=S3Object(connection=connection),
|
|
75
|
+
s3_bucket=S3Bucket(connection=connection),
|
|
76
|
+
default_bucket=bucket_name
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
file_service = FileSystemService(
|
|
80
|
+
dynamodb=db,
|
|
81
|
+
table_name=table_name,
|
|
82
|
+
s3_service=s3_service,
|
|
83
|
+
default_bucket=bucket_name
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# Delete file
|
|
87
|
+
result = file_service.delete(
|
|
88
|
+
resource_id=file_id,
|
|
89
|
+
tenant_id=tenant_id,
|
|
90
|
+
user_id=user_id,
|
|
91
|
+
hard_delete=hard_delete
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
if result.success:
|
|
95
|
+
delete_type = "permanently" if hard_delete else "soft"
|
|
96
|
+
return {
|
|
97
|
+
'statusCode': 200,
|
|
98
|
+
'body': json.dumps({
|
|
99
|
+
'success': True,
|
|
100
|
+
'message': f'File {delete_type} deleted successfully'
|
|
101
|
+
})
|
|
102
|
+
}
|
|
103
|
+
else:
|
|
104
|
+
status_code = 404 if result.error_code == 'NOT_FOUND' else 403
|
|
105
|
+
return {
|
|
106
|
+
'statusCode': status_code,
|
|
107
|
+
'body': json.dumps({
|
|
108
|
+
'success': False,
|
|
109
|
+
'message': result.message,
|
|
110
|
+
'error_code': result.error_code
|
|
111
|
+
})
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
except Exception as e:
|
|
115
|
+
return {
|
|
116
|
+
'statusCode': 500,
|
|
117
|
+
'body': json.dumps({
|
|
118
|
+
'success': False,
|
|
119
|
+
'message': f'Internal server error: {str(e)}'
|
|
120
|
+
})
|
|
121
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Lambda handler for file download.
|
|
3
|
+
|
|
4
|
+
Geek Cafe, LLC
|
|
5
|
+
MIT License. See Project Root for the license information.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import base64
|
|
10
|
+
import os
|
|
11
|
+
from typing import Dict, Any
|
|
12
|
+
|
|
13
|
+
from boto3_assist.dynamodb.dynamodb import DynamoDB
|
|
14
|
+
from boto3_assist.s3.s3_connection import S3Connection
|
|
15
|
+
from boto3_assist.s3.s3_object import S3Object
|
|
16
|
+
from boto3_assist.s3.s3_bucket import S3Bucket
|
|
17
|
+
|
|
18
|
+
from geek_cafe_saas_sdk.domains.files.services.file_system_service import FileSystemService
|
|
19
|
+
from geek_cafe_saas_sdk.domains.files.services.s3_file_service import S3FileService
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, Any]:
|
|
23
|
+
"""
|
|
24
|
+
Download file handler.
|
|
25
|
+
|
|
26
|
+
Expected Event:
|
|
27
|
+
{
|
|
28
|
+
"pathParameters": {
|
|
29
|
+
"file_id": "file-123"
|
|
30
|
+
},
|
|
31
|
+
"queryStringParameters": {
|
|
32
|
+
"tenant_id": "tenant-456",
|
|
33
|
+
"user_id": "user-789",
|
|
34
|
+
"presigned": "true" # Optional, return presigned URL instead
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
Returns (Direct Download):
|
|
39
|
+
{
|
|
40
|
+
"statusCode": 200,
|
|
41
|
+
"isBase64Encoded": true,
|
|
42
|
+
"headers": {
|
|
43
|
+
"Content-Type": "application/pdf",
|
|
44
|
+
"Content-Disposition": "attachment; filename=document.pdf"
|
|
45
|
+
},
|
|
46
|
+
"body": "base64_encoded_file_content"
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
Returns (Presigned URL):
|
|
50
|
+
{
|
|
51
|
+
"statusCode": 200,
|
|
52
|
+
"body": {
|
|
53
|
+
"success": true,
|
|
54
|
+
"data": {
|
|
55
|
+
"download_url": "https://s3.amazonaws.com/..."
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
"""
|
|
60
|
+
try:
|
|
61
|
+
# Extract parameters
|
|
62
|
+
path_params = event.get('pathParameters', {})
|
|
63
|
+
query_params = event.get('queryStringParameters', {})
|
|
64
|
+
|
|
65
|
+
file_id = path_params.get('file_id')
|
|
66
|
+
tenant_id = query_params.get('tenant_id')
|
|
67
|
+
user_id = query_params.get('user_id')
|
|
68
|
+
presigned = query_params.get('presigned', 'false').lower() == 'true'
|
|
69
|
+
expires_in = int(query_params.get('expires_in', '300'))
|
|
70
|
+
|
|
71
|
+
# Validate required fields
|
|
72
|
+
if not all([file_id, tenant_id, user_id]):
|
|
73
|
+
return {
|
|
74
|
+
'statusCode': 400,
|
|
75
|
+
'body': json.dumps({
|
|
76
|
+
'success': False,
|
|
77
|
+
'message': 'Missing required parameters: file_id, tenant_id, user_id'
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
# Initialize services
|
|
82
|
+
table_name = os.environ.get('DYNAMODB_TABLE_NAME', 'files-table')
|
|
83
|
+
bucket_name = os.environ.get('S3_BUCKET_NAME', 'files-bucket')
|
|
84
|
+
|
|
85
|
+
db = DynamoDB()
|
|
86
|
+
connection = S3Connection()
|
|
87
|
+
|
|
88
|
+
s3_service = S3FileService(
|
|
89
|
+
s3_object=S3Object(connection=connection),
|
|
90
|
+
s3_bucket=S3Bucket(connection=connection),
|
|
91
|
+
default_bucket=bucket_name
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
file_service = FileSystemService(
|
|
95
|
+
dynamodb=db,
|
|
96
|
+
table_name=table_name,
|
|
97
|
+
s3_service=s3_service,
|
|
98
|
+
default_bucket=bucket_name
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
# Return presigned URL if requested
|
|
102
|
+
if presigned:
|
|
103
|
+
url_result = file_service.generate_download_url(
|
|
104
|
+
tenant_id=tenant_id,
|
|
105
|
+
file_id=file_id,
|
|
106
|
+
user_id=user_id,
|
|
107
|
+
expires_in=expires_in
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
if url_result.success:
|
|
111
|
+
return {
|
|
112
|
+
'statusCode': 200,
|
|
113
|
+
'body': json.dumps({
|
|
114
|
+
'success': True,
|
|
115
|
+
'data': {
|
|
116
|
+
'download_url': url_result.data,
|
|
117
|
+
'expires_in': expires_in
|
|
118
|
+
}
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
else:
|
|
122
|
+
return {
|
|
123
|
+
'statusCode': 404 if url_result.error_code == 'NOT_FOUND' else 403,
|
|
124
|
+
'body': json.dumps({
|
|
125
|
+
'success': False,
|
|
126
|
+
'message': url_result.message,
|
|
127
|
+
'error_code': url_result.error_code
|
|
128
|
+
})
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
# Get file metadata
|
|
132
|
+
file_result = file_service.get_by_id(
|
|
133
|
+
resource_id=file_id,
|
|
134
|
+
tenant_id=tenant_id,
|
|
135
|
+
user_id=user_id
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
if not file_result.success:
|
|
139
|
+
return {
|
|
140
|
+
'statusCode': 404 if file_result.error_code == 'NOT_FOUND' else 403,
|
|
141
|
+
'body': json.dumps({
|
|
142
|
+
'success': False,
|
|
143
|
+
'message': file_result.message,
|
|
144
|
+
'error_code': file_result.error_code
|
|
145
|
+
})
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
file = file_result.data
|
|
149
|
+
|
|
150
|
+
# Download file content
|
|
151
|
+
download_result = file_service.download_file(
|
|
152
|
+
tenant_id=tenant_id,
|
|
153
|
+
file_id=file_id,
|
|
154
|
+
user_id=user_id
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
if download_result.success:
|
|
158
|
+
file_data = download_result.data
|
|
159
|
+
|
|
160
|
+
# Return file as base64-encoded response
|
|
161
|
+
return {
|
|
162
|
+
'statusCode': 200,
|
|
163
|
+
'isBase64Encoded': True,
|
|
164
|
+
'headers': {
|
|
165
|
+
'Content-Type': file.mime_type,
|
|
166
|
+
'Content-Disposition': f'attachment; filename="{file.file_name}"'
|
|
167
|
+
},
|
|
168
|
+
'body': base64.b64encode(file_data).decode('utf-8')
|
|
169
|
+
}
|
|
170
|
+
else:
|
|
171
|
+
return {
|
|
172
|
+
'statusCode': 500,
|
|
173
|
+
'body': json.dumps({
|
|
174
|
+
'success': False,
|
|
175
|
+
'message': download_result.message,
|
|
176
|
+
'error_code': download_result.error_code
|
|
177
|
+
})
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
except Exception as e:
|
|
181
|
+
return {
|
|
182
|
+
'statusCode': 500,
|
|
183
|
+
'body': json.dumps({
|
|
184
|
+
'success': False,
|
|
185
|
+
'message': f'Internal server error: {str(e)}'
|
|
186
|
+
})
|
|
187
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Lambda handler for getting file metadata.
|
|
3
|
+
|
|
4
|
+
Geek Cafe, LLC
|
|
5
|
+
MIT License. See Project Root for the license information.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
from typing import Dict, Any
|
|
11
|
+
|
|
12
|
+
from boto3_assist.dynamodb.dynamodb import DynamoDB
|
|
13
|
+
from boto3_assist.s3.s3_connection import S3Connection
|
|
14
|
+
from boto3_assist.s3.s3_object import S3Object
|
|
15
|
+
from boto3_assist.s3.s3_bucket import S3Bucket
|
|
16
|
+
|
|
17
|
+
from geek_cafe_saas_sdk.domains.files.services.file_system_service import FileSystemService
|
|
18
|
+
from geek_cafe_saas_sdk.domains.files.services.s3_file_service import S3FileService
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, Any]:
|
|
22
|
+
"""
|
|
23
|
+
Get file metadata handler.
|
|
24
|
+
|
|
25
|
+
Expected Event:
|
|
26
|
+
{
|
|
27
|
+
"pathParameters": {
|
|
28
|
+
"file_id": "file-123"
|
|
29
|
+
},
|
|
30
|
+
"queryStringParameters": {
|
|
31
|
+
"tenant_id": "tenant-456",
|
|
32
|
+
"user_id": "user-789"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
{
|
|
38
|
+
"statusCode": 200,
|
|
39
|
+
"body": {
|
|
40
|
+
"success": true,
|
|
41
|
+
"data": {
|
|
42
|
+
"file_id": "file-123",
|
|
43
|
+
"file_name": "document.pdf",
|
|
44
|
+
"file_size": 12345,
|
|
45
|
+
"mime_type": "application/pdf",
|
|
46
|
+
"directory_id": "dir-789",
|
|
47
|
+
"owner_id": "user-456",
|
|
48
|
+
"created_utc_ts": 1234567890.0,
|
|
49
|
+
"tags": ["report", "monthly"]
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
"""
|
|
54
|
+
try:
|
|
55
|
+
# Extract parameters
|
|
56
|
+
path_params = event.get('pathParameters', {})
|
|
57
|
+
query_params = event.get('queryStringParameters', {})
|
|
58
|
+
|
|
59
|
+
file_id = path_params.get('file_id')
|
|
60
|
+
tenant_id = query_params.get('tenant_id')
|
|
61
|
+
user_id = query_params.get('user_id')
|
|
62
|
+
|
|
63
|
+
# Validate required fields
|
|
64
|
+
if not all([file_id, tenant_id, user_id]):
|
|
65
|
+
return {
|
|
66
|
+
'statusCode': 400,
|
|
67
|
+
'body': json.dumps({
|
|
68
|
+
'success': False,
|
|
69
|
+
'message': 'Missing required parameters: file_id, tenant_id, user_id'
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
# Initialize services
|
|
74
|
+
table_name = os.environ.get('DYNAMODB_TABLE_NAME', 'files-table')
|
|
75
|
+
bucket_name = os.environ.get('S3_BUCKET_NAME', 'files-bucket')
|
|
76
|
+
|
|
77
|
+
db = DynamoDB()
|
|
78
|
+
connection = S3Connection()
|
|
79
|
+
|
|
80
|
+
s3_service = S3FileService(
|
|
81
|
+
s3_object=S3Object(connection=connection),
|
|
82
|
+
s3_bucket=S3Bucket(connection=connection),
|
|
83
|
+
default_bucket=bucket_name
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
file_service = FileSystemService(
|
|
87
|
+
dynamodb=db,
|
|
88
|
+
table_name=table_name,
|
|
89
|
+
s3_service=s3_service,
|
|
90
|
+
default_bucket=bucket_name
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
# Get file
|
|
94
|
+
result = file_service.get_by_id(
|
|
95
|
+
resource_id=file_id,
|
|
96
|
+
tenant_id=tenant_id,
|
|
97
|
+
user_id=user_id
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
if result.success:
|
|
101
|
+
file = result.data
|
|
102
|
+
return {
|
|
103
|
+
'statusCode': 200,
|
|
104
|
+
'body': json.dumps({
|
|
105
|
+
'success': True,
|
|
106
|
+
'data': file.to_dictionary()
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
else:
|
|
110
|
+
status_code = 404 if result.error_code == 'NOT_FOUND' else 403
|
|
111
|
+
return {
|
|
112
|
+
'statusCode': status_code,
|
|
113
|
+
'body': json.dumps({
|
|
114
|
+
'success': False,
|
|
115
|
+
'message': result.message,
|
|
116
|
+
'error_code': result.error_code
|
|
117
|
+
})
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
except Exception as e:
|
|
121
|
+
return {
|
|
122
|
+
'statusCode': 500,
|
|
123
|
+
'body': json.dumps({
|
|
124
|
+
'success': False,
|
|
125
|
+
'message': f'Internal server error: {str(e)}'
|
|
126
|
+
})
|
|
127
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Lambda handler for listing files.
|
|
3
|
+
|
|
4
|
+
Geek Cafe, LLC
|
|
5
|
+
MIT License. See Project Root for the license information.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
from typing import Dict, Any
|
|
11
|
+
|
|
12
|
+
from boto3_assist.dynamodb.dynamodb import DynamoDB
|
|
13
|
+
from boto3_assist.s3.s3_connection import S3Connection
|
|
14
|
+
from boto3_assist.s3.s3_object import S3Object
|
|
15
|
+
from boto3_assist.s3.s3_bucket import S3Bucket
|
|
16
|
+
|
|
17
|
+
from geek_cafe_saas_sdk.domains.files.services.file_system_service import FileSystemService
|
|
18
|
+
from geek_cafe_saas_sdk.domains.files.services.s3_file_service import S3FileService
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, Any]:
|
|
22
|
+
"""List files handler."""
|
|
23
|
+
try:
|
|
24
|
+
query_params = event.get('queryStringParameters', {})
|
|
25
|
+
|
|
26
|
+
tenant_id = query_params.get('tenant_id')
|
|
27
|
+
user_id = query_params.get('user_id')
|
|
28
|
+
directory_id = query_params.get('directory_id')
|
|
29
|
+
owner_id = query_params.get('owner_id')
|
|
30
|
+
limit = int(query_params.get('limit', '100'))
|
|
31
|
+
|
|
32
|
+
if not all([tenant_id, user_id]):
|
|
33
|
+
return {
|
|
34
|
+
'statusCode': 400,
|
|
35
|
+
'body': json.dumps({
|
|
36
|
+
'success': False,
|
|
37
|
+
'message': 'Missing required parameters'
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
table_name = os.environ.get('DYNAMODB_TABLE_NAME', 'files-table')
|
|
42
|
+
bucket_name = os.environ.get('S3_BUCKET_NAME', 'files-bucket')
|
|
43
|
+
|
|
44
|
+
db = DynamoDB()
|
|
45
|
+
connection = S3Connection()
|
|
46
|
+
|
|
47
|
+
s3_service = S3FileService(
|
|
48
|
+
s3_object=S3Object(connection=connection),
|
|
49
|
+
s3_bucket=S3Bucket(connection=connection),
|
|
50
|
+
default_bucket=bucket_name
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
file_service = FileSystemService(
|
|
54
|
+
dynamodb=db,
|
|
55
|
+
table_name=table_name,
|
|
56
|
+
s3_service=s3_service,
|
|
57
|
+
default_bucket=bucket_name
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
if directory_id:
|
|
61
|
+
result = file_service.list_files_by_directory(
|
|
62
|
+
tenant_id=tenant_id,
|
|
63
|
+
directory_id=directory_id,
|
|
64
|
+
user_id=user_id,
|
|
65
|
+
limit=limit
|
|
66
|
+
)
|
|
67
|
+
elif owner_id:
|
|
68
|
+
result = file_service.list_files_by_owner(
|
|
69
|
+
tenant_id=tenant_id,
|
|
70
|
+
owner_id=owner_id,
|
|
71
|
+
user_id=user_id,
|
|
72
|
+
limit=limit
|
|
73
|
+
)
|
|
74
|
+
else:
|
|
75
|
+
return {
|
|
76
|
+
'statusCode': 400,
|
|
77
|
+
'body': json.dumps({
|
|
78
|
+
'success': False,
|
|
79
|
+
'message': 'Must provide directory_id or owner_id'
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if result.success:
|
|
84
|
+
return {
|
|
85
|
+
'statusCode': 200,
|
|
86
|
+
'body': json.dumps({
|
|
87
|
+
'success': True,
|
|
88
|
+
'data': [f.to_dictionary() for f in result.data],
|
|
89
|
+
'count': len(result.data)
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
else:
|
|
93
|
+
return {
|
|
94
|
+
'statusCode': 400,
|
|
95
|
+
'body': json.dumps({
|
|
96
|
+
'success': False,
|
|
97
|
+
'message': result.message
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
except Exception as e:
|
|
102
|
+
return {
|
|
103
|
+
'statusCode': 500,
|
|
104
|
+
'body': json.dumps({
|
|
105
|
+
'success': False,
|
|
106
|
+
'message': str(e)
|
|
107
|
+
})
|
|
108
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Lambda handler for sharing files.
|
|
3
|
+
|
|
4
|
+
Geek Cafe, LLC
|
|
5
|
+
MIT License. See Project Root for the license information.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
from typing import Dict, Any
|
|
11
|
+
|
|
12
|
+
from boto3_assist.dynamodb.dynamodb import DynamoDB
|
|
13
|
+
from geek_cafe_saas_sdk.domains.files.services.file_share_service import FileShareService
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, Any]:
|
|
17
|
+
"""Share file handler."""
|
|
18
|
+
try:
|
|
19
|
+
if isinstance(event.get('body'), str):
|
|
20
|
+
body = json.loads(event['body'])
|
|
21
|
+
else:
|
|
22
|
+
body = event.get('body', {})
|
|
23
|
+
|
|
24
|
+
tenant_id = body.get('tenant_id')
|
|
25
|
+
user_id = body.get('user_id')
|
|
26
|
+
file_id = body.get('file_id')
|
|
27
|
+
shared_with_user_id = body.get('shared_with_user_id')
|
|
28
|
+
permission = body.get('permission', 'view')
|
|
29
|
+
expires_at = body.get('expires_at')
|
|
30
|
+
message = body.get('message')
|
|
31
|
+
|
|
32
|
+
if not all([tenant_id, user_id, file_id, shared_with_user_id]):
|
|
33
|
+
return {
|
|
34
|
+
'statusCode': 400,
|
|
35
|
+
'body': json.dumps({
|
|
36
|
+
'success': False,
|
|
37
|
+
'message': 'Missing required fields'
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
table_name = os.environ.get('DYNAMODB_TABLE_NAME', 'files-table')
|
|
42
|
+
db = DynamoDB()
|
|
43
|
+
|
|
44
|
+
share_service = FileShareService(
|
|
45
|
+
dynamodb=db,
|
|
46
|
+
table_name=table_name
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
result = share_service.create(
|
|
50
|
+
tenant_id=tenant_id,
|
|
51
|
+
user_id=user_id,
|
|
52
|
+
file_id=file_id,
|
|
53
|
+
shared_with_user_id=shared_with_user_id,
|
|
54
|
+
permission=permission,
|
|
55
|
+
expires_at=expires_at,
|
|
56
|
+
message=message
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
if result.success:
|
|
60
|
+
return {
|
|
61
|
+
'statusCode': 201,
|
|
62
|
+
'body': json.dumps({
|
|
63
|
+
'success': True,
|
|
64
|
+
'data': result.data.to_dictionary()
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
else:
|
|
68
|
+
return {
|
|
69
|
+
'statusCode': 400,
|
|
70
|
+
'body': json.dumps({
|
|
71
|
+
'success': False,
|
|
72
|
+
'message': result.message
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
except Exception as e:
|
|
77
|
+
return {
|
|
78
|
+
'statusCode': 500,
|
|
79
|
+
'body': json.dumps({
|
|
80
|
+
'success': False,
|
|
81
|
+
'message': str(e)
|
|
82
|
+
})
|
|
83
|
+
}
|