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,180 @@
1
+ import hashlib
2
+ import secrets
3
+ import string
4
+ import uuid
5
+ import time
6
+ from geek_cafe_saas_sdk.utilities.logging_utility import LoggingUtility
7
+ from geek_cafe_saas_sdk.utilities.datetime_utility import DatetimeUtility
8
+
9
+ logger = LoggingUtility(__name__).logger
10
+
11
+
12
+ class StringFunctions:
13
+ SPECIAL_CHARACTERS = "!\\#$%&()*+,-.:;<=>?@[]^_{|}~"
14
+
15
+ @staticmethod
16
+ def generate_random_string(length=12, digits=True, letters=True, special=False):
17
+ characters = ""
18
+ if letters:
19
+ characters += string.ascii_letters
20
+ if digits:
21
+ characters += string.digits
22
+ if special:
23
+ characters += StringFunctions.SPECIAL_CHARACTERS
24
+
25
+ random_string = "".join(secrets.choice(characters) for _ in range(length))
26
+ return random_string
27
+
28
+ @staticmethod
29
+ def generate_random_password(length=15, digits=True, letters=True, special=True):
30
+ characters = ""
31
+ # we have a min lenght requirement of 8
32
+ if length < 8:
33
+ length = 8
34
+
35
+ if letters:
36
+ characters += string.ascii_letters
37
+ if digits:
38
+ characters += string.digits
39
+ if special:
40
+ characters += StringFunctions.SPECIAL_CHARACTERS
41
+
42
+ if len(characters) == 0:
43
+ raise RuntimeError(
44
+ "You must choose at least one of the options: digits, letters, special"
45
+ )
46
+
47
+ # Ensure at least two characters from each selected set are included
48
+ password = []
49
+ if letters:
50
+ # lower
51
+ password.append(secrets.choice(string.ascii_lowercase))
52
+ password.append(secrets.choice(string.ascii_lowercase))
53
+ # upper
54
+ password.append(secrets.choice(string.ascii_uppercase))
55
+ password.append(secrets.choice(string.ascii_uppercase))
56
+ if digits:
57
+ password.append(secrets.choice(string.digits))
58
+ password.append(secrets.choice(string.digits))
59
+ if special:
60
+ password.append(secrets.choice(StringFunctions.SPECIAL_CHARACTERS))
61
+ password.append(secrets.choice(StringFunctions.SPECIAL_CHARACTERS))
62
+
63
+ # Fill the remaining length with random characters from the selected sets
64
+ remaining_length = length - len(password)
65
+ password.extend(secrets.choice(characters) for _ in range(remaining_length))
66
+
67
+ # Shuffle the password to randomize the order of characters
68
+ secrets.SystemRandom().shuffle(password)
69
+
70
+ return "".join(password)
71
+
72
+ @staticmethod
73
+ def wrap_text(text: str, max_width: int):
74
+ """Wrap text at a specified width."""
75
+ wrapped_text = ""
76
+ if not text:
77
+ return text
78
+
79
+ while len(text) > max_width:
80
+ # Find the maximum width position, breaking at max_width
81
+ # If there are no spaces to break on, break at max_width directly
82
+ break_point = (
83
+ text.rfind(" ", 0, max_width) if " " in text[0:max_width] else max_width
84
+ )
85
+ if break_point == -1: # no spaces found, hard break
86
+ break_point = max_width
87
+ wrapped_text += text[:break_point] + "\n"
88
+ text = text[break_point:].lstrip() # remove any leading space
89
+ wrapped_text += text
90
+ return wrapped_text
91
+
92
+ @staticmethod
93
+ def generate_uuid():
94
+ return str(uuid.uuid4())
95
+
96
+ @staticmethod
97
+ def generate_hash(input_string: str) -> str:
98
+ """
99
+ Generates a SHA-256 hash for the given input string.
100
+
101
+ Args:
102
+ input_string (str): The string to hash.
103
+
104
+ Returns:
105
+ str: The resulting hash value as a hexadecimal string.
106
+ """
107
+ # Encode the input string to bytes
108
+ encoded_string = input_string.encode()
109
+
110
+ # Create a SHA-256 hash object
111
+ hash_object = hashlib.sha256()
112
+
113
+ # Update the hash object with the encoded string
114
+ hash_object.update(encoded_string)
115
+
116
+ # Get the hexadecimal representation of the hash
117
+ hash_hex = hash_object.hexdigest()
118
+
119
+ return hash_hex
120
+
121
+ @staticmethod
122
+ def generate_sortable_uuid():
123
+ """
124
+ Generates a unique id for the execution event
125
+ """
126
+ epoch_time = time.time()
127
+ sortable_uuid: uuid.UUID = DatetimeUtility.uuid1_utc(timestamp=epoch_time)
128
+
129
+ time_stamp = str(epoch_time).replace(".", "-")
130
+ sortable_id = f"{time_stamp}:{str(sortable_uuid)}"
131
+ return sortable_id
132
+
133
+ @staticmethod
134
+ def to_bool(value: str | bool | int | None) -> bool:
135
+ """
136
+ Converts a string or boolean value to a boolean.
137
+
138
+ Args:
139
+ value (str | bool | int | None): The value to convert.
140
+
141
+ Returns:
142
+ bool: The converted boolean value.
143
+
144
+ Raises:
145
+ ValueError: If the input value is not a valid boolean or string representation.
146
+ """
147
+ return StringFunctions.to_boolean(value)
148
+
149
+ @staticmethod
150
+ def to_boolean(value: str | bool | int | None) -> bool:
151
+ """
152
+ Converts a string or boolean value to a boolean.
153
+
154
+ Args:
155
+ value (str | bool | int | None): The value to convert.
156
+
157
+ Returns:
158
+ bool: The converted boolean value.
159
+
160
+ Raises:
161
+ ValueError: If the input value is not a valid boolean or string representation.
162
+ """
163
+ if isinstance(value, bool):
164
+ return value
165
+ if isinstance(value, str):
166
+ value = str(value).lower().strip()
167
+ if value in ("true", "1", "t", "y", "yes"):
168
+ return True
169
+ if value in ("false", "0", "f", "n", "no"):
170
+ return False
171
+ else:
172
+ logger.warning(f"Invalid boolean value: {value}; returning False.")
173
+ return False
174
+
175
+ elif isinstance(value, int):
176
+ return bool(value)
177
+ elif value is None:
178
+ return False
179
+ else:
180
+ raise ValueError(f"Invalid boolean value: {value}")
@@ -0,0 +1,397 @@
1
+ Metadata-Version: 2.4
2
+ Name: geek_cafe_saas_sdk
3
+ Version: 0.6.0
4
+ Summary: Base Reusable Services for SaaS
5
+ Project-URL: Homepage, https://github.com/geekcafe/geek-cafe-services
6
+ Project-URL: Documentation, https://github.com/geekcafe/geek-cafe-services/blob/main/README.md
7
+ Project-URL: Source Code, https://github.com/geekcafe/geek-cafe-services
8
+ Author-email: Eric Wilson <eric.wilson@geekcafe.com>
9
+ License: Geek Cafe Services Business Source License 1.0
10
+
11
+ Copyright (c) 2025 Geek Cafe, LLC. All rights reserved.
12
+
13
+ The "Geek Cafe Services" software (the "Software") is made available under this
14
+ Business Source License (the "License"). This License allows you to view,
15
+ study, and modify the source code, and to use it for personal, educational,
16
+ research, or non-commercial purposes, subject to the following terms.
17
+
18
+ 1. Grant of Rights
19
+ a. You may copy and modify the Software for your own personal,
20
+ educational, or internal development use.
21
+ b. You may not use the Software, or modified versions of it,
22
+ to provide any commercial service or product, including
23
+ software-as-a-service, consulting, hosting, or resale,
24
+ without a separate commercial license from Geek Cafe LLC.
25
+
26
+ 2. Change Date
27
+ Three (3) years from the date of first public release of a specific
28
+ version of the Software (the “Change Date”), that version will
29
+ automatically be made available under the Apache License 2.0.
30
+ Later versions may have different Change Dates.
31
+
32
+ 3. Attribution
33
+ All copies or substantial portions of the Software must retain this
34
+ License text, the copyright notice above, and a clear reference to
35
+ the original source repository (https://github.com/geekcafe/geek-cafe-services).
36
+
37
+ 4. Trademarks
38
+ The names “Geek Cafe”, “Geek Cafe Services”, and any related logos are
39
+ trademarks of Geek Cafe LLC and may not be used to endorse or promote
40
+ derivative products without prior written permission.
41
+
42
+ 5. Disclaimer of Warranty
43
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
44
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
45
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT.
46
+
47
+ 6. Limitation of Liability
48
+ IN NO EVENT SHALL GEEK Cafe LLC OR CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
49
+ DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR
50
+ OTHERWISE, ARISING FROM OR IN CONNECTION WITH THE SOFTWARE OR ITS USE.
51
+
52
+ ---
53
+
54
+ For commercial licensing inquiries, contact:
55
+ legal@geekcafe.com
56
+ License-File: LICENSE
57
+ Keywords: api gateway,aws,dynamodb,lambda,saas,serverless,services
58
+ Classifier: Development Status :: 4 - Beta
59
+ Classifier: Framework :: AWS CDK
60
+ Classifier: Intended Audience :: Developers
61
+ Classifier: License :: OSI Approved :: MIT License
62
+ Classifier: Programming Language :: Python :: 3
63
+ Classifier: Programming Language :: Python :: 3.8
64
+ Classifier: Programming Language :: Python :: 3.9
65
+ Classifier: Programming Language :: Python :: 3.10
66
+ Classifier: Programming Language :: Python :: 3.11
67
+ Classifier: Programming Language :: Python :: 3.12
68
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
69
+ Requires-Python: >=3.8
70
+ Requires-Dist: boto3-assist
71
+ Provides-Extra: dev
72
+ Requires-Dist: build; extra == 'dev'
73
+ Requires-Dist: twine; extra == 'dev'
74
+ Description-Content-Type: text/markdown
75
+
76
+ # Geek Cafe Services
77
+
78
+ [![Python 3.13+](https://img.shields.io/badge/python-3.13+-blue.svg)](https://www.python.org/downloads/)
79
+ [![Version](https://img.shields.io/badge/version-0.4.0-green.svg)](https://github.com/geekcafe/geek-cafe-services)
80
+ [![DynamoDB](https://img.shields.io/badge/database-DynamoDB-orange.svg)](https://aws.amazon.com/dynamodb/)
81
+ [![AWS Lambda](https://img.shields.io/badge/runtime-AWS%20Lambda-yellow.svg)](https://aws.amazon.com/lambda/)
82
+
83
+ > **⚠️ Pre-1.0 Notice**: This library is under active development. Breaking changes may occur until we reach a stable 1.0 GA release. We recommend pinning to specific versions in production.
84
+
85
+ > **✨ New in v0.3.0**: Complete CRUDL Lambda handlers for all core resources (Events, Users, Groups, Messages, Votes)!
86
+
87
+ <!-- COVERAGE-BADGE:START -->
88
+ ## Test Coverage
89
+
90
+ ![Tests](https://img.shields.io/badge/tests-1127%20passed-brightgreen)
91
+ ![Coverage](https://img.shields.io/badge/coverage-82.9%25-green)
92
+
93
+ **Overall Coverage:** 82.9% (9325/11242 statements)
94
+
95
+ ### Coverage Summary
96
+
97
+ | Metric | Value |
98
+ |--------|-------|
99
+ | Total Statements | 11,242 |
100
+ | Covered Statements | 9,325 |
101
+ | Missing Statements | 1,917 |
102
+ | Coverage Percentage | 82.9% |
103
+ | Total Tests | 1127 |
104
+ | Test Status | ✅ All Passing |
105
+
106
+ ### Files Needing Attention (< 80% coverage)
107
+
108
+ | Coverage | Missing Lines | File |
109
+ |----------|---------------|------|
110
+ | 17.5% | 47 | `lambda_handlers/_base/authorized_secure_handler.py` |
111
+ | 25.3% | 133 | `domains/communities/services/community_member_service.py` |
112
+ | 46.3% | 58 | `domains/auth/models/role.py` |
113
+ | 46.9% | 34 | `domains/auth/models/permission.py` |
114
+ | 46.9% | 85 | `domains/auth/services/resource_permission_service.py` |
115
+ | 56.2% | 7 | `lambda_handlers/_base/secure_handler.py` |
116
+ | 58.5% | 17 | `domains/messaging/handlers/contact_threads/update/app.py` |
117
+ | 62.3% | 118 | `utilities/lambda_event_utility.py` |
118
+ | 63.4% | 86 | `domains/communities/services/community_service.py` |
119
+ | 64.0% | 41 | `domains/files/services/s3_file_service.py` |
120
+
121
+ *... and 20 more files with < 80% coverage*
122
+
123
+ ### Running Tests
124
+
125
+ ```bash
126
+ # Run all tests with coverage
127
+ ./run_unit_tests.sh
128
+
129
+ # View detailed coverage report
130
+ open reports/coverage/index.html
131
+ ```
132
+
133
+ *Last updated: 2025-10-15 22:38:06*
134
+
135
+ ---
136
+
137
+ <!-- COVERAGE-BADGE:END -->
138
+
139
+ ## Description
140
+
141
+ **Geek Cafe Services** is a production-ready, enterprise-grade library that provides reusable database services specifically designed for multi-tenant SaaS applications. Built on top of AWS DynamoDB, this library offers a prescriptive approach to building scalable, maintainable backend services with consistent patterns and best practices.
142
+
143
+ ### Why Geek Cafe Services?
144
+
145
+ 🏗️ **Consistent Architecture**: All services follow the same proven patterns for CRUD operations, error handling, and access control
146
+ 🔒 **Multi-Tenant by Design**: Built-in tenant isolation ensures secure data separation across customers
147
+ ⚡ **DynamoDB Optimized**: Leverages DynamoDB's strengths with efficient GSI indexes and query patterns
148
+ 🛡️ **Production Ready**: Comprehensive error handling, logging, pagination, and batch operations
149
+ 🧪 **Fully Tested**: 100% test coverage with comprehensive test suites for reliability
150
+ 📖 **Well Documented**: Extensive documentation with practical examples and best practices
151
+
152
+ ### Perfect For
153
+
154
+ - **SaaS Applications** requiring multi-tenant data isolation
155
+ - **Serverless Architectures** built on AWS Lambda and DynamoDB
156
+ - **Teams** wanting consistent, proven patterns across services
157
+ - **Rapid Development** with pre-built, tested service components
158
+
159
+ ## Installation
160
+
161
+ ```bash
162
+ # Clone the repository
163
+ git clone https://github.com/geekcafe/geek-cafe-services.git
164
+ cd geek-cafe-services
165
+
166
+ # Setup the development environment
167
+ ./pysetup.sh
168
+
169
+ # Install dependencies
170
+ pip install -r requirements.txt
171
+ ```
172
+
173
+ ## Quick Start
174
+
175
+ ```python
176
+ from geek_cafe_saas_sdk.message_service import MessageService
177
+
178
+ # Initialize service
179
+ service = MessageService()
180
+
181
+ # Create a message
182
+ result = service.create(
183
+ tenant_id="your_tenant",
184
+ user_id="your_user",
185
+ type="notification",
186
+ content={"title": "Welcome!", "body": "Thanks for joining us."}
187
+ )
188
+
189
+ if result.success:
190
+ print(f"Created message: {result.data.id}")
191
+ ```
192
+
193
+ ## Available Services
194
+
195
+ ### 🚀 Lambda Handler Wrappers (NEW in v0.2.0)
196
+ **Purpose**: Eliminate 70-80% of boilerplate code in AWS Lambda functions
197
+
198
+ **Key Capabilities**:
199
+ - ✅ Automatic API key validation from environment
200
+ - ✅ Request body parsing and camelCase → snake_case conversion
201
+ - ✅ Service initialization with connection pooling for warm starts
202
+ - ✅ Built-in CORS and error handling
203
+ - ✅ User context extraction from authorizers
204
+ - ✅ Service injection for easy testing
205
+ - ✅ Support for public and secured endpoints
206
+
207
+ **Available Handlers**:
208
+ - `ApiKeyLambdaHandler` - API key validation (most common)
209
+ - `PublicLambdaHandler` - No authentication (config endpoints)
210
+ - `BaseLambdaHandler` - Extensible base for custom handlers
211
+
212
+ **Quick Example**:
213
+ ```python
214
+ from geek_cafe_saas_sdk.lambda_handlers import ApiKeyLambdaHandler
215
+ from geek_cafe_saas_sdk.vote_service import VoteService
216
+
217
+ # All boilerplate handled in 3 lines
218
+ handler = ApiKeyLambdaHandler(
219
+ service_class=VoteService,
220
+ require_body=True,
221
+ convert_case=True
222
+ )
223
+
224
+ def lambda_handler(event, context):
225
+ return handler.execute(event, context, create_vote)
226
+
227
+ def create_vote(event, service, user_context):
228
+ # Just your business logic - everything else is handled!
229
+ payload = event["parsed_body"] # Already parsed & converted
230
+ return service.create_vote(
231
+ tenant_id=user_context.get("tenant_id", "anonymous"),
232
+ user_id=user_context.get("user_id", "anonymous"),
233
+ **payload
234
+ )
235
+ ```
236
+
237
+ **Use Cases**: Any AWS Lambda function with API key auth, reducing code by 70-80% while maintaining all functionality
238
+
239
+ 📖 **[Complete Lambda Handlers Documentation](./docs/lambda_handlers.md)**
240
+
241
+ ### 📧 MessageService
242
+ **Purpose**: Complete message and notification management system
243
+
244
+ **Key Capabilities**:
245
+ - ✅ Full CRUD operations with tenant isolation
246
+ - ✅ Flexible JSON content storage for any message type
247
+ - ✅ Efficient querying by user, tenant, and message type
248
+ - ✅ Automatic audit trails and timestamps
249
+ - ✅ Built-in access control and validation
250
+
251
+ **Use Cases**: User notifications, system alerts, communication logs, announcement management
252
+
253
+ ### 🗳️ Voting Services Suite
254
+ **Purpose**: Complete voting and rating system with real-time aggregation
255
+
256
+ **Architecture**: Three interconnected services working together:
257
+
258
+ #### VoteService
259
+ - ✅ Individual vote management with automatic upsert behavior
260
+ - ✅ One vote per user per target enforcement
261
+ - ✅ Support for up/down votes or custom vote types
262
+ - ✅ Comprehensive querying by user, target, and tenant
263
+
264
+ #### VoteSummaryService
265
+ - ✅ Pre-calculated vote totals for instant retrieval
266
+ - ✅ Target-based optimization for high-performance lookups
267
+ - ✅ Metadata tracking (last tallied timestamp, vote counts)
268
+ - ✅ Tenant-scoped summary management
269
+
270
+ #### VoteTallyService
271
+ - ✅ Intelligent vote aggregation with pagination support
272
+ - ✅ Batch processing for multiple targets
273
+ - ✅ Stale target detection and automated re-tallying
274
+ - ✅ Comprehensive error handling and resilience
275
+
276
+ **Use Cases**: Product ratings, content voting, feedback systems, community polls, recommendation engines
277
+
278
+ ## Documentation
279
+
280
+ 📖 **[Complete Documentation](./docs/services_overview.md)**
281
+
282
+ - **[DynamoDB Models](./docs/dynamodb_models.md)** - Model definition patterns and best practices
283
+ - **[Services Pattern](./docs/services_pattern.md)** - Service layer architecture and CRUD operations
284
+ - **[Lambda Handlers](./docs/lambda_handlers.md)** - 🆕 Eliminate Lambda boilerplate (70-80% code reduction)
285
+ - [Services Overview](./docs/services_overview.md) - Architecture and common patterns
286
+ - [MessageService](./docs/message_service.md) - Message management API
287
+ - [Voting Services](./docs/voting_services.md) - Complete voting system documentation
288
+ - [A/B Testing Guide](./docs/ab_testing_guide.md) - Using voting services for A/B testing and experimentation
289
+ - [Development Roadmap](./docs/roadmap.md) - Planned improvements and enhancements
290
+
291
+ ## Core Features
292
+
293
+ ### 🏛️ **Enterprise Architecture**
294
+ - **Multi-Tenant by Design**: Complete tenant isolation with automatic access control
295
+ - **Consistent Patterns**: All services follow identical CRUD interfaces and conventions
296
+ - **Scalable Design**: Built for high-throughput, multi-customer SaaS applications
297
+
298
+ ### 🔧 **Developer Experience**
299
+ - **Type Safety**: Full Python type hints for better IDE support and fewer bugs
300
+ - **Comprehensive Testing**: 100% test coverage with realistic test scenarios
301
+ - **Rich Documentation**: Detailed API docs, examples, and best practices
302
+ - **Easy Integration**: Simple initialization and consistent error handling
303
+
304
+ ### ⚡ **Performance & Reliability**
305
+ - **DynamoDB Optimized**: Efficient GSI indexes and query patterns for fast operations
306
+ - **Pagination Support**: Handle large datasets without memory issues
307
+ - **Batch Operations**: Process multiple items efficiently
308
+ - **Error Resilience**: Graceful handling of partial failures and edge cases
309
+
310
+ ### 🛡️ **Production Ready**
311
+ - **Structured Logging**: AWS Lambda Powertools integration for observability
312
+ - **Comprehensive Validation**: Input validation with detailed error messages
313
+ - **Access Control**: Automatic tenant and user-based security enforcement
314
+ - **Audit Trails**: Complete tracking of who did what and when
315
+
316
+ ## Environment Setup
317
+
318
+ ```bash
319
+ # Required environment variables
320
+ export DYNAMODB_TABLE_NAME=your_table_name
321
+
322
+ # Optional AWS configuration (if not using IAM roles)
323
+ export AWS_REGION=us-east-1
324
+ export AWS_ACCESS_KEY_ID=your_access_key
325
+ export AWS_SECRET_ACCESS_KEY=your_secret_key
326
+ ```
327
+
328
+ ## Testing
329
+
330
+ ```bash
331
+ # Run all tests
332
+ pytest tests/ -v
333
+
334
+ # Run specific service tests
335
+ pytest tests/test_message_service.py -v
336
+ pytest tests/test_vote_*_service.py -v
337
+
338
+ # Run with coverage
339
+ pytest tests/ --cov=geek_cafe_saas_sdk --cov-report=html
340
+ ```
341
+
342
+ ## Project Structure
343
+
344
+ ```
345
+ geek-cafe-services/
346
+ ├── src/geek_cafe_saas_sdk/
347
+ │ ├── lambda_handlers/ # 🆕 Lambda handler wrappers (v0.2.0)
348
+ │ │ ├── base.py # Base handler with common functionality
349
+ │ │ ├── api_key_handler.py # API key validation handler
350
+ │ │ ├── public_handler.py # Public (no auth) handler
351
+ │ │ └── service_pool.py # Service connection pooling
352
+ │ ├── middleware/ # CORS, auth, error handling decorators
353
+ │ ├── utilities/ # Request/response helpers
354
+ │ ├── models/ # Data models with DynamoDB mapping
355
+ │ ├── *_service.py # Service implementations
356
+ │ ├── database_service.py # Base service class
357
+ │ └── service_result.py # Standardized response wrapper
358
+ ├── tests/ # Comprehensive test suite
359
+ ├── docs/ # Detailed documentation
360
+ │ └── lambda_handlers.md # 🆕 Lambda wrapper documentation
361
+ ├── examples/ # Working code examples
362
+ │ └── lambda_handlers/ # 🆕 Handler examples
363
+ └── README.md # This file
364
+ ```
365
+
366
+ ## Contributing
367
+
368
+ We welcome contributions! Here's how to get started:
369
+
370
+ 1. **Fork the repository** and create a feature branch
371
+ 2. **Follow the existing patterns** - consistency is key
372
+ 3. **Add comprehensive tests** for any new functionality
373
+ 4. **Update documentation** for API changes
374
+ 5. **Submit a Pull Request** with a clear description
375
+
376
+ ### Development Guidelines
377
+
378
+ - Follow existing code style and patterns
379
+ - Maintain 100% test coverage for new code
380
+ - Update documentation for any API changes
381
+ - Use meaningful commit messages
382
+ - Test against multiple Python versions if possible
383
+
384
+ ## License
385
+
386
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
387
+
388
+ ## Support
389
+
390
+ - 📖 **Documentation**: [Complete docs](./docs/services_overview.md)
391
+ - 🐛 **Bug Reports**: [GitHub Issues](https://github.com/geekcafe/geek-cafe-services/issues)
392
+ - 💡 **Feature Requests**: [GitHub Discussions](https://github.com/geekcafe/geek-cafe-services/discussions)
393
+ - 📧 **Questions**: Create an issue with the "question" label
394
+
395
+ ---
396
+
397
+ **Built with ❤️ for the SaaS development community**