done
Browse files- App/Android/Android.py +24 -1
- App/Subscriptions/SubscriptionRoutes.py +17 -1
- App/Templates/Templates.py +5 -2
- App/Users/Model.py +38 -0
- App/Users/UserRoutes.py +16 -12
App/Android/Android.py
CHANGED
@@ -49,6 +49,16 @@ class AndroidClient:
|
|
49 |
response = await self.client.post(f"/logout/{phone}")
|
50 |
return APIResponse(**response.json())
|
51 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
@require_base_url
|
53 |
async def get_active_users(self) -> APIResponse:
|
54 |
"""Retrieve all active users."""
|
@@ -57,8 +67,15 @@ class AndroidClient:
|
|
57 |
return APIResponse(**response.json())
|
58 |
|
59 |
@require_base_url
|
60 |
-
async def
|
61 |
"""Enable or disable a user."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
path = f"/users/{request.phone}/disable"
|
63 |
response = await self.client.post(path, json=None)
|
64 |
return APIResponse(**response.json())
|
@@ -112,3 +129,9 @@ class AndroidClient:
|
|
112 |
await self.enable_user(request=request)
|
113 |
# Replace this with actual API call logic
|
114 |
return {"status": "success", "message": "User activated."}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
response = await self.client.post(f"/logout/{phone}")
|
50 |
return APIResponse(**response.json())
|
51 |
|
52 |
+
@require_base_url
|
53 |
+
async def is_user_active(self, phone_number):
|
54 |
+
"""Retrieve all active users."""
|
55 |
+
response = await self.client.get("/users/active")
|
56 |
+
active_users = response.json()["active_users"]
|
57 |
+
|
58 |
+
for user in active_users:
|
59 |
+
if phone_number == user["phone"]:
|
60 |
+
return True
|
61 |
+
|
62 |
@require_base_url
|
63 |
async def get_active_users(self) -> APIResponse:
|
64 |
"""Retrieve all active users."""
|
|
|
67 |
return APIResponse(**response.json())
|
68 |
|
69 |
@require_base_url
|
70 |
+
async def remove_session(self, phone_number) -> APIResponse:
|
71 |
"""Enable or disable a user."""
|
72 |
+
path = f"/users/{phone_number}/remove-session"
|
73 |
+
response = await self.client.post(path, json=None)
|
74 |
+
return APIResponse(**response.json())
|
75 |
+
|
76 |
+
@require_base_url
|
77 |
+
async def disable_user(self, request: SetUserStatusRequest) -> APIResponse:
|
78 |
+
"""disable a user."""
|
79 |
path = f"/users/{request.phone}/disable"
|
80 |
response = await self.client.post(path, json=None)
|
81 |
return APIResponse(**response.json())
|
|
|
129 |
await self.enable_user(request=request)
|
130 |
# Replace this with actual API call logic
|
131 |
return {"status": "success", "message": "User activated."}
|
132 |
+
|
133 |
+
async def deactivate_user(self, phone_number: str):
|
134 |
+
request = SetUserStatusRequest(phone=phone_number, disabled=False)
|
135 |
+
await self.disable_user(request=request)
|
136 |
+
# Replace this with actual API call logic
|
137 |
+
return {"status": "success", "message": "User activated."}
|
App/Subscriptions/SubscriptionRoutes.py
CHANGED
@@ -145,13 +145,29 @@ async def update_usage(subscription_id: str, request: UpdateUsageRequest):
|
|
145 |
"/subscription/{subscription_id}/deactivate", response_model=BaseResponse
|
146 |
)
|
147 |
async def deactivate_subscription(subscription_id: str):
|
|
|
148 |
subscription = await Subscription.get_or_none(id=subscription_id)
|
149 |
if not subscription:
|
150 |
raise HTTPException(
|
151 |
status_code=status.HTTP_404_NOT_FOUND, detail="Subscription not found"
|
152 |
)
|
153 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
154 |
subscription.active = False
|
155 |
await subscription.save()
|
156 |
|
157 |
-
|
|
|
|
|
|
|
|
|
|
|
|
145 |
"/subscription/{subscription_id}/deactivate", response_model=BaseResponse
|
146 |
)
|
147 |
async def deactivate_subscription(subscription_id: str):
|
148 |
+
# Fetch the subscription by ID
|
149 |
subscription = await Subscription.get_or_none(id=subscription_id)
|
150 |
if not subscription:
|
151 |
raise HTTPException(
|
152 |
status_code=status.HTTP_404_NOT_FOUND, detail="Subscription not found"
|
153 |
)
|
154 |
|
155 |
+
# Fetch the associated user
|
156 |
+
user = await subscription.user
|
157 |
+
plan = await subscription.plan
|
158 |
+
if not user:
|
159 |
+
raise HTTPException(
|
160 |
+
status_code=status.HTTP_404_NOT_FOUND,
|
161 |
+
detail="User not found for subscription",
|
162 |
+
)
|
163 |
+
|
164 |
+
# Deactivate the subscription
|
165 |
subscription.active = False
|
166 |
await subscription.save()
|
167 |
|
168 |
+
# Deactivate the user associated with this subscription
|
169 |
+
await user.deactivate_user()
|
170 |
+
await user.send_subcription_expired_message(plan=plan)
|
171 |
+
return BaseResponse(
|
172 |
+
code=200, message="Subscription and user deactivated successfully"
|
173 |
+
)
|
App/Templates/Templates.py
CHANGED
@@ -61,5 +61,8 @@ class MessageTemplate:
|
|
61 |
def balance_assigned_message(self, amount: Decimal, new_balance: Decimal) -> str:
|
62 |
return f"Habari! Salio la {amount} limeongezwa kwa mafanikio kwenye akaunti yako. Salio lako jipya ni {new_balance}."
|
63 |
|
64 |
-
|
65 |
-
|
|
|
|
|
|
|
|
61 |
def balance_assigned_message(self, amount: Decimal, new_balance: Decimal) -> str:
|
62 |
return f"Habari! Salio la {amount} limeongezwa kwa mafanikio kwenye akaunti yako. Salio lako jipya ni {new_balance}."
|
63 |
|
64 |
+
def subscription_expired_message(
|
65 |
+
self, user_name: str, plan_name: str, business_name=BUSINESS
|
66 |
+
) -> str:
|
67 |
+
"""Generates a message when the subscription is over."""
|
68 |
+
return f"Habari {user_name}, Bando lako la {plan_name}, limeisha. "
|
App/Users/Model.py
CHANGED
@@ -318,3 +318,41 @@ class User(models.Model):
|
|
318 |
except Exception as e:
|
319 |
logger.error(f"Error activating user {self.phoneNumber}: {str(e)}")
|
320 |
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
318 |
except Exception as e:
|
319 |
logger.error(f"Error activating user {self.phoneNumber}: {str(e)}")
|
320 |
return False
|
321 |
+
|
322 |
+
async def deactivate_user(self):
|
323 |
+
|
324 |
+
self.account_locked = True
|
325 |
+
await self.save()
|
326 |
+
await self.remover_user_session()
|
327 |
+
|
328 |
+
try:
|
329 |
+
await self.android_client.deactivate_user(self.phoneNumber)
|
330 |
+
except Exception as e:
|
331 |
+
logger.error(f"Failed to deactivate user {self.phoneNumber}: {e}")
|
332 |
+
raise e # Raise the error after logging
|
333 |
+
|
334 |
+
async def send_subcription_expired_message(self, plan: Plan):
|
335 |
+
try:
|
336 |
+
message = self.message_templates.subscription_expired_message(
|
337 |
+
user_name=self.name, plan_name=plan.name
|
338 |
+
)
|
339 |
+
await self.send_message(message=message)
|
340 |
+
logger.info(f"Subscription expired message sent to {self.phoneNumber}.")
|
341 |
+
except Exception as e:
|
342 |
+
logger.error(
|
343 |
+
f"Failed to send subscription expired message to {self.phoneNumber}: {e}"
|
344 |
+
)
|
345 |
+
raise e
|
346 |
+
|
347 |
+
async def is_active(self):
|
348 |
+
try:
|
349 |
+
return await self.android_client.is_user_active(self.phoneNumber)
|
350 |
+
except Exception as e:
|
351 |
+
raise e
|
352 |
+
|
353 |
+
async def remover_user_session(self):
|
354 |
+
try:
|
355 |
+
await self.android_client.remove_session(self.phoneNumber)
|
356 |
+
except Exception as e:
|
357 |
+
logger.error(f"Failed to remove session for {self.phoneNumber}: {e}")
|
358 |
+
raise e # Raise the error after logging
|
App/Users/UserRoutes.py
CHANGED
@@ -63,10 +63,11 @@ async def register_user(request: RegisterUserRequest):
|
|
63 |
)
|
64 |
async def login_user(request: LoginUserRequest):
|
65 |
# Find user by phone number
|
66 |
-
db_user = await User.filter(phoneNumber=request.phoneNumber).first()
|
67 |
valid_password = await db_user.verify_password(request.password)
|
68 |
# Check if user exists and password is correct
|
69 |
if db_user and valid_password:
|
|
|
70 |
# Fetch active subscription if it exists
|
71 |
subscription = await Subscription.filter(user=db_user, active=True).first()
|
72 |
|
@@ -75,6 +76,9 @@ async def login_user(request: LoginUserRequest):
|
|
75 |
subscription.expiration_time.isoformat() if subscription else None
|
76 |
)
|
77 |
|
|
|
|
|
|
|
78 |
access_token = create_access_token(
|
79 |
data={
|
80 |
"user_name": db_user.name,
|
@@ -145,17 +149,17 @@ async def get_all_users():
|
|
145 |
return [UserResponse.from_orm(user) for user in users]
|
146 |
|
147 |
|
148 |
-
@user_router.delete(
|
149 |
-
|
150 |
-
)
|
151 |
-
async def delete_user(user_id: str):
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
|
160 |
|
161 |
@user_router.put(
|
|
|
63 |
)
|
64 |
async def login_user(request: LoginUserRequest):
|
65 |
# Find user by phone number
|
66 |
+
db_user: User = await User.filter(phoneNumber=request.phoneNumber).first()
|
67 |
valid_password = await db_user.verify_password(request.password)
|
68 |
# Check if user exists and password is correct
|
69 |
if db_user and valid_password:
|
70 |
+
|
71 |
# Fetch active subscription if it exists
|
72 |
subscription = await Subscription.filter(user=db_user, active=True).first()
|
73 |
|
|
|
76 |
subscription.expiration_time.isoformat() if subscription else None
|
77 |
)
|
78 |
|
79 |
+
is_active = await db_user.is_active()
|
80 |
+
if is_active:
|
81 |
+
await db_user.remover_user_session()
|
82 |
access_token = create_access_token(
|
83 |
data={
|
84 |
"user_name": db_user.name,
|
|
|
149 |
return [UserResponse.from_orm(user) for user in users]
|
150 |
|
151 |
|
152 |
+
# @user_router.delete(
|
153 |
+
# "/user/{user_id}", response_model=BaseResponse, status_code=status.HTTP_200_OK
|
154 |
+
# )
|
155 |
+
# async def delete_user(user_id: str):
|
156 |
+
# user = await User.filter(id=user_id).first()
|
157 |
+
# if not user:
|
158 |
+
# raise HTTPException(
|
159 |
+
# status_code=status.HTTP_404_NOT_FOUND, detail="User not found."
|
160 |
+
# )
|
161 |
+
# await user.delete()
|
162 |
+
# return BaseResponse(code=200, message="User deleted successfully.")
|
163 |
|
164 |
|
165 |
@user_router.put(
|