geek-cafe-saas-sdk 0.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of geek-cafe-saas-sdk might be problematic. Click here for more details.

Files changed (194) hide show
  1. geek_cafe_saas_sdk/__init__.py +9 -0
  2. geek_cafe_saas_sdk/core/__init__.py +11 -0
  3. geek_cafe_saas_sdk/core/audit_mixin.py +33 -0
  4. geek_cafe_saas_sdk/core/error_codes.py +132 -0
  5. geek_cafe_saas_sdk/core/service_errors.py +19 -0
  6. geek_cafe_saas_sdk/core/service_result.py +121 -0
  7. geek_cafe_saas_sdk/decorators/__init__.py +64 -0
  8. geek_cafe_saas_sdk/decorators/auth.py +373 -0
  9. geek_cafe_saas_sdk/decorators/core.py +358 -0
  10. geek_cafe_saas_sdk/domains/__init__.py +0 -0
  11. geek_cafe_saas_sdk/domains/analytics/__init__.py +0 -0
  12. geek_cafe_saas_sdk/domains/analytics/handlers/__init__.py +0 -0
  13. geek_cafe_saas_sdk/domains/analytics/models/__init__.py +9 -0
  14. geek_cafe_saas_sdk/domains/analytics/models/website_analytics.py +219 -0
  15. geek_cafe_saas_sdk/domains/analytics/models/website_analytics_summary.py +220 -0
  16. geek_cafe_saas_sdk/domains/analytics/services/__init__.py +11 -0
  17. geek_cafe_saas_sdk/domains/analytics/services/website_analytics_service.py +232 -0
  18. geek_cafe_saas_sdk/domains/analytics/services/website_analytics_summary_service.py +212 -0
  19. geek_cafe_saas_sdk/domains/analytics/services/website_analytics_tally_service.py +610 -0
  20. geek_cafe_saas_sdk/domains/auth/__init__.py +0 -0
  21. geek_cafe_saas_sdk/domains/auth/handlers/__init__.py +0 -0
  22. geek_cafe_saas_sdk/domains/auth/handlers/users/create/app.py +41 -0
  23. geek_cafe_saas_sdk/domains/auth/handlers/users/delete/app.py +41 -0
  24. geek_cafe_saas_sdk/domains/auth/handlers/users/get/app.py +39 -0
  25. geek_cafe_saas_sdk/domains/auth/handlers/users/list/app.py +36 -0
  26. geek_cafe_saas_sdk/domains/auth/handlers/users/update/app.py +44 -0
  27. geek_cafe_saas_sdk/domains/auth/models/__init__.py +13 -0
  28. geek_cafe_saas_sdk/domains/auth/models/permission.py +134 -0
  29. geek_cafe_saas_sdk/domains/auth/models/resource_permission.py +245 -0
  30. geek_cafe_saas_sdk/domains/auth/models/role.py +213 -0
  31. geek_cafe_saas_sdk/domains/auth/models/user.py +285 -0
  32. geek_cafe_saas_sdk/domains/auth/services/__init__.py +16 -0
  33. geek_cafe_saas_sdk/domains/auth/services/authorization_service.py +376 -0
  34. geek_cafe_saas_sdk/domains/auth/services/permission_registry.py +464 -0
  35. geek_cafe_saas_sdk/domains/auth/services/resource_permission_service.py +408 -0
  36. geek_cafe_saas_sdk/domains/auth/services/user_service.py +274 -0
  37. geek_cafe_saas_sdk/domains/communities/__init__.py +0 -0
  38. geek_cafe_saas_sdk/domains/communities/handlers/__init__.py +0 -0
  39. geek_cafe_saas_sdk/domains/communities/handlers/communities/create/app.py +41 -0
  40. geek_cafe_saas_sdk/domains/communities/handlers/communities/delete/app.py +41 -0
  41. geek_cafe_saas_sdk/domains/communities/handlers/communities/get/app.py +39 -0
  42. geek_cafe_saas_sdk/domains/communities/handlers/communities/list/app.py +36 -0
  43. geek_cafe_saas_sdk/domains/communities/handlers/communities/update/app.py +44 -0
  44. geek_cafe_saas_sdk/domains/communities/models/__init__.py +6 -0
  45. geek_cafe_saas_sdk/domains/communities/models/community.py +326 -0
  46. geek_cafe_saas_sdk/domains/communities/models/community_member.py +227 -0
  47. geek_cafe_saas_sdk/domains/communities/services/__init__.py +6 -0
  48. geek_cafe_saas_sdk/domains/communities/services/community_member_service.py +412 -0
  49. geek_cafe_saas_sdk/domains/communities/services/community_service.py +479 -0
  50. geek_cafe_saas_sdk/domains/events/__init__.py +0 -0
  51. geek_cafe_saas_sdk/domains/events/handlers/__init__.py +0 -0
  52. geek_cafe_saas_sdk/domains/events/handlers/attendees/app.py +67 -0
  53. geek_cafe_saas_sdk/domains/events/handlers/cancel/app.py +66 -0
  54. geek_cafe_saas_sdk/domains/events/handlers/check_in/app.py +60 -0
  55. geek_cafe_saas_sdk/domains/events/handlers/create/app.py +93 -0
  56. geek_cafe_saas_sdk/domains/events/handlers/delete/app.py +42 -0
  57. geek_cafe_saas_sdk/domains/events/handlers/get/app.py +39 -0
  58. geek_cafe_saas_sdk/domains/events/handlers/invite/app.py +98 -0
  59. geek_cafe_saas_sdk/domains/events/handlers/list/app.py +125 -0
  60. geek_cafe_saas_sdk/domains/events/handlers/publish/app.py +49 -0
  61. geek_cafe_saas_sdk/domains/events/handlers/rsvp/app.py +83 -0
  62. geek_cafe_saas_sdk/domains/events/handlers/update/app.py +44 -0
  63. geek_cafe_saas_sdk/domains/events/models/__init__.py +3 -0
  64. geek_cafe_saas_sdk/domains/events/models/event.py +681 -0
  65. geek_cafe_saas_sdk/domains/events/models/event_attendee.py +324 -0
  66. geek_cafe_saas_sdk/domains/events/services/__init__.py +9 -0
  67. geek_cafe_saas_sdk/domains/events/services/event_attendee_service.py +571 -0
  68. geek_cafe_saas_sdk/domains/events/services/event_service.py +684 -0
  69. geek_cafe_saas_sdk/domains/files/__init__.py +0 -0
  70. geek_cafe_saas_sdk/domains/files/models/__init__.py +0 -0
  71. geek_cafe_saas_sdk/domains/files/models/directory.py +258 -0
  72. geek_cafe_saas_sdk/domains/files/models/file.py +312 -0
  73. geek_cafe_saas_sdk/domains/files/models/file_share.py +268 -0
  74. geek_cafe_saas_sdk/domains/files/models/file_version.py +216 -0
  75. geek_cafe_saas_sdk/domains/files/services/__init__.py +0 -0
  76. geek_cafe_saas_sdk/domains/files/services/directory_service.py +701 -0
  77. geek_cafe_saas_sdk/domains/files/services/file_share_service.py +663 -0
  78. geek_cafe_saas_sdk/domains/files/services/file_system_service.py +575 -0
  79. geek_cafe_saas_sdk/domains/files/services/file_version_service.py +739 -0
  80. geek_cafe_saas_sdk/domains/files/services/s3_file_service.py +501 -0
  81. geek_cafe_saas_sdk/domains/messaging/__init__.py +0 -0
  82. geek_cafe_saas_sdk/domains/messaging/handlers/__init__.py +0 -0
  83. geek_cafe_saas_sdk/domains/messaging/handlers/chat_channels/create/app.py +86 -0
  84. geek_cafe_saas_sdk/domains/messaging/handlers/chat_channels/delete/app.py +65 -0
  85. geek_cafe_saas_sdk/domains/messaging/handlers/chat_channels/get/app.py +64 -0
  86. geek_cafe_saas_sdk/domains/messaging/handlers/chat_channels/list/app.py +97 -0
  87. geek_cafe_saas_sdk/domains/messaging/handlers/chat_channels/update/app.py +149 -0
  88. geek_cafe_saas_sdk/domains/messaging/handlers/chat_messages/create/app.py +67 -0
  89. geek_cafe_saas_sdk/domains/messaging/handlers/chat_messages/delete/app.py +65 -0
  90. geek_cafe_saas_sdk/domains/messaging/handlers/chat_messages/get/app.py +64 -0
  91. geek_cafe_saas_sdk/domains/messaging/handlers/chat_messages/list/app.py +102 -0
  92. geek_cafe_saas_sdk/domains/messaging/handlers/chat_messages/update/app.py +127 -0
  93. geek_cafe_saas_sdk/domains/messaging/handlers/contact_threads/create/app.py +94 -0
  94. geek_cafe_saas_sdk/domains/messaging/handlers/contact_threads/delete/app.py +66 -0
  95. geek_cafe_saas_sdk/domains/messaging/handlers/contact_threads/get/app.py +67 -0
  96. geek_cafe_saas_sdk/domains/messaging/handlers/contact_threads/list/app.py +95 -0
  97. geek_cafe_saas_sdk/domains/messaging/handlers/contact_threads/update/app.py +156 -0
  98. geek_cafe_saas_sdk/domains/messaging/models/__init__.py +13 -0
  99. geek_cafe_saas_sdk/domains/messaging/models/chat_channel.py +337 -0
  100. geek_cafe_saas_sdk/domains/messaging/models/chat_channel_member.py +180 -0
  101. geek_cafe_saas_sdk/domains/messaging/models/chat_message.py +426 -0
  102. geek_cafe_saas_sdk/domains/messaging/models/contact_thread.py +392 -0
  103. geek_cafe_saas_sdk/domains/messaging/services/__init__.py +11 -0
  104. geek_cafe_saas_sdk/domains/messaging/services/chat_channel_service.py +700 -0
  105. geek_cafe_saas_sdk/domains/messaging/services/chat_message_service.py +491 -0
  106. geek_cafe_saas_sdk/domains/messaging/services/contact_thread_service.py +497 -0
  107. geek_cafe_saas_sdk/domains/tenancy/__init__.py +0 -0
  108. geek_cafe_saas_sdk/domains/tenancy/handlers/__init__.py +0 -0
  109. geek_cafe_saas_sdk/domains/tenancy/handlers/subscriptions/activate/app.py +52 -0
  110. geek_cafe_saas_sdk/domains/tenancy/handlers/subscriptions/active/app.py +37 -0
  111. geek_cafe_saas_sdk/domains/tenancy/handlers/subscriptions/cancel/app.py +55 -0
  112. geek_cafe_saas_sdk/domains/tenancy/handlers/subscriptions/get/app.py +39 -0
  113. geek_cafe_saas_sdk/domains/tenancy/handlers/subscriptions/list/app.py +44 -0
  114. geek_cafe_saas_sdk/domains/tenancy/handlers/subscriptions/record_payment/app.py +56 -0
  115. geek_cafe_saas_sdk/domains/tenancy/handlers/tenants/get/app.py +39 -0
  116. geek_cafe_saas_sdk/domains/tenancy/handlers/tenants/me/app.py +37 -0
  117. geek_cafe_saas_sdk/domains/tenancy/handlers/tenants/signup/app.py +61 -0
  118. geek_cafe_saas_sdk/domains/tenancy/handlers/tenants/update/app.py +44 -0
  119. geek_cafe_saas_sdk/domains/tenancy/models/__init__.py +6 -0
  120. geek_cafe_saas_sdk/domains/tenancy/models/subscription.py +440 -0
  121. geek_cafe_saas_sdk/domains/tenancy/models/tenant.py +258 -0
  122. geek_cafe_saas_sdk/domains/tenancy/services/__init__.py +6 -0
  123. geek_cafe_saas_sdk/domains/tenancy/services/subscription_service.py +557 -0
  124. geek_cafe_saas_sdk/domains/tenancy/services/tenant_service.py +575 -0
  125. geek_cafe_saas_sdk/domains/voting/__init__.py +0 -0
  126. geek_cafe_saas_sdk/domains/voting/handlers/__init__.py +0 -0
  127. geek_cafe_saas_sdk/domains/voting/handlers/votes/create/app.py +128 -0
  128. geek_cafe_saas_sdk/domains/voting/handlers/votes/delete/app.py +41 -0
  129. geek_cafe_saas_sdk/domains/voting/handlers/votes/get/app.py +39 -0
  130. geek_cafe_saas_sdk/domains/voting/handlers/votes/list/app.py +38 -0
  131. geek_cafe_saas_sdk/domains/voting/handlers/votes/summerize/README.md +3 -0
  132. geek_cafe_saas_sdk/domains/voting/handlers/votes/update/app.py +44 -0
  133. geek_cafe_saas_sdk/domains/voting/models/__init__.py +9 -0
  134. geek_cafe_saas_sdk/domains/voting/models/vote.py +231 -0
  135. geek_cafe_saas_sdk/domains/voting/models/vote_summary.py +193 -0
  136. geek_cafe_saas_sdk/domains/voting/services/__init__.py +11 -0
  137. geek_cafe_saas_sdk/domains/voting/services/vote_service.py +264 -0
  138. geek_cafe_saas_sdk/domains/voting/services/vote_summary_service.py +198 -0
  139. geek_cafe_saas_sdk/domains/voting/services/vote_tally_service.py +533 -0
  140. geek_cafe_saas_sdk/lambda_handlers/README.md +404 -0
  141. geek_cafe_saas_sdk/lambda_handlers/__init__.py +67 -0
  142. geek_cafe_saas_sdk/lambda_handlers/_base/__init__.py +25 -0
  143. geek_cafe_saas_sdk/lambda_handlers/_base/api_key_handler.py +129 -0
  144. geek_cafe_saas_sdk/lambda_handlers/_base/authorized_secure_handler.py +218 -0
  145. geek_cafe_saas_sdk/lambda_handlers/_base/base_handler.py +185 -0
  146. geek_cafe_saas_sdk/lambda_handlers/_base/handler_factory.py +256 -0
  147. geek_cafe_saas_sdk/lambda_handlers/_base/public_handler.py +53 -0
  148. geek_cafe_saas_sdk/lambda_handlers/_base/secure_handler.py +89 -0
  149. geek_cafe_saas_sdk/lambda_handlers/_base/service_pool.py +94 -0
  150. geek_cafe_saas_sdk/lambda_handlers/directories/create/app.py +79 -0
  151. geek_cafe_saas_sdk/lambda_handlers/directories/delete/app.py +76 -0
  152. geek_cafe_saas_sdk/lambda_handlers/directories/get/app.py +74 -0
  153. geek_cafe_saas_sdk/lambda_handlers/directories/list/app.py +75 -0
  154. geek_cafe_saas_sdk/lambda_handlers/directories/move/app.py +79 -0
  155. geek_cafe_saas_sdk/lambda_handlers/files/delete/app.py +121 -0
  156. geek_cafe_saas_sdk/lambda_handlers/files/download/app.py +187 -0
  157. geek_cafe_saas_sdk/lambda_handlers/files/get/app.py +127 -0
  158. geek_cafe_saas_sdk/lambda_handlers/files/list/app.py +108 -0
  159. geek_cafe_saas_sdk/lambda_handlers/files/share/app.py +83 -0
  160. geek_cafe_saas_sdk/lambda_handlers/files/shares/list/app.py +84 -0
  161. geek_cafe_saas_sdk/lambda_handlers/files/shares/revoke/app.py +76 -0
  162. geek_cafe_saas_sdk/lambda_handlers/files/update/app.py +143 -0
  163. geek_cafe_saas_sdk/lambda_handlers/files/upload/app.py +151 -0
  164. geek_cafe_saas_sdk/middleware/__init__.py +36 -0
  165. geek_cafe_saas_sdk/middleware/auth.py +85 -0
  166. geek_cafe_saas_sdk/middleware/authorization.py +523 -0
  167. geek_cafe_saas_sdk/middleware/cors.py +63 -0
  168. geek_cafe_saas_sdk/middleware/error_handling.py +114 -0
  169. geek_cafe_saas_sdk/middleware/validation.py +80 -0
  170. geek_cafe_saas_sdk/models/__init__.py +20 -0
  171. geek_cafe_saas_sdk/models/base_model.py +233 -0
  172. geek_cafe_saas_sdk/services/__init__.py +18 -0
  173. geek_cafe_saas_sdk/services/database_service.py +441 -0
  174. geek_cafe_saas_sdk/utilities/__init__.py +88 -0
  175. geek_cafe_saas_sdk/utilities/cognito_utility.py +568 -0
  176. geek_cafe_saas_sdk/utilities/custom_exceptions.py +183 -0
  177. geek_cafe_saas_sdk/utilities/datetime_utility.py +410 -0
  178. geek_cafe_saas_sdk/utilities/dictionary_utility.py +78 -0
  179. geek_cafe_saas_sdk/utilities/dynamodb_utils.py +151 -0
  180. geek_cafe_saas_sdk/utilities/environment_loader.py +149 -0
  181. geek_cafe_saas_sdk/utilities/environment_variables.py +228 -0
  182. geek_cafe_saas_sdk/utilities/http_body_parameters.py +44 -0
  183. geek_cafe_saas_sdk/utilities/http_path_parameters.py +60 -0
  184. geek_cafe_saas_sdk/utilities/http_status_code.py +63 -0
  185. geek_cafe_saas_sdk/utilities/jwt_utility.py +234 -0
  186. geek_cafe_saas_sdk/utilities/lambda_event_utility.py +776 -0
  187. geek_cafe_saas_sdk/utilities/logging_utility.py +64 -0
  188. geek_cafe_saas_sdk/utilities/message_query_helper.py +340 -0
  189. geek_cafe_saas_sdk/utilities/response.py +209 -0
  190. geek_cafe_saas_sdk/utilities/string_functions.py +180 -0
  191. geek_cafe_saas_sdk-0.6.0.dist-info/METADATA +397 -0
  192. geek_cafe_saas_sdk-0.6.0.dist-info/RECORD +194 -0
  193. geek_cafe_saas_sdk-0.6.0.dist-info/WHEEL +4 -0
  194. geek_cafe_saas_sdk-0.6.0.dist-info/licenses/LICENSE +47 -0
@@ -0,0 +1,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
+ }