If an account is suspended for more than 7 days, it must be deleted in my case. Currently, I have three ideas:
-
- Create an another cronjob folder and write a script to use cronjob to periodically execute this Python file. (Can I use the MongoDB connection method in
base.py
for sharing, or do I need to write it separately?)
- Create an another cronjob folder and write a script to use cronjob to periodically execute this Python file. (Can I use the MongoDB connection method in
-
- Implement an API to delete accounts in
authentication.py
and set up a cronjob to periodically call this API.
- Implement an API to delete accounts in
-
-
Write the functionality in
user.py
and useif __name__ == "__main__":
to call that function.(You can check function
delete_suspended_accounts
below.)
-
What would be the best practices to implement this functionality? Or do you have other suggestions? Thank you.
For more information, you can check my code structure.
- Implement account APIs in
authentication.py
, such as registration, password reset, account suspension, account reactivation, and account blocking. - Implement MongoDB connection in
base.py
. - Implement database logic operations for account APIs in
user.py
.
.
└── fastapi-backend
├── assets
├── static
├── src
│ ├── api
│ │ ├── api_router.py
│ │ └── authentication.py
│ ├── db
│ │ ├── base.py
│ │ └── user.py
│ ├── models
│ └── services
└── utils
base.py
from pymongo import MongoClient
import urllib
from fastapi import Depends
from src.core.config import setting
from typing import Callable, Type
class Base:
def __init__(self, connection: MongoClient) -> None:
self._conn = connection.demo
@property
def connection(self):
return self._conn
def _get_mongo_client():
return MongoClient(setting.MONGO_URL, maxPoolSize=None)
def get_repository(repo_type: Type[Base]) -> Callable:
async def _get_repo(conn: MongoClient = Depends(_get_mongo_client)):
yield repo_type(conn)
return _get_repo
user.py
class UserRepository(Base):
def __init__(self, conn):
super().__init__(conn)
def suspend_user(self, user_id: str):
the_user = self.connection.user.find_one({'_id': ObjectId(user_id)})
if the_user and the_user['status'] == Status.ACTIVATED.value:
self.connection.user.update(the_user, {"$set": {'status': Status.SUSPENDED.value,
'suspended_date': datetime.datetime.now()}})
else:
raise HTTPException(status_code=400, detail=u'Not Activated')
def delete_suspended_accounts(self):
query = {"status": 'Status.SUSPENDED.value', "suspended_date": {"$lt": datetime.datetime.utcnow() - timedelta(days=7)}}
result = self.connection.user.delete_many(query)
return result.deleted_count
authentication.py
@authentication.post('/suspend')
async def suspend_account(request: Request, token: str,
user_repository: UserRepository = Depends(get_repository(UserRepository))):
try:
# decode access token
access_token = jwt.decode(token, key=setting.SECERT_KEY)
# suspend user
user_id = access_token['sub']
user_repository.suspend_user(user_id=user_id)
except DecodeError:
return {'message': 'decode error'}
except ExpiredSignatureError:
return {'message': 'expired signature error'}
return {'message': 'ok'}
I tried the first method as follows, writing a script and then executing it with a cronjob, which worked successfully. However, my tech leader suggested that I write it in user.py
. But since FastAPI uses dependency injection (Depends) to connect to MongoDB, how should I write it for the best approach? Or are there any other methods you would recommend? Thank you.
from pymongo import MongoClient
from datetime import datetime, timedelta
client = MongoClient("MONGO_URL")
db = client['demo']
collection = db['user']
def delete_suspended_accounts():
query = {"status": 3, "suspended_date": {"$lt": datetime.utcnow() - timedelta(days=7)}}
result = collection.delete_many(query)
print(f"Deleted {result.deleted_count} suspended accounts.")
if __name__ == "__main__":
delete_suspended_accounts()
4
I created another folder called cronjob and placed delete_account.py
inside it. You can just browse the code below.
.
└── fastapi-backend
├── assets
├── static
├── cronjob
│ └── delete_account.py
├── src
│ ├── api
│ │ ├── api_rounter.py
│ │ └── authentication.py
│ ├── db
│ │ ├── base.py
│ │ └── user.py
│ ├── models
│ └── services
└── utils
import sys
sys.path.insert(0, '../')
from src.db.users import UserRepository
from src.db.base import _get_mongo_client
conn = _get_mongo_client()
if __name__ == "__main__":
user_repo = UserRepository(conn)
counts = user_repo.delete_suspended_accounts()
print(f"Deleted {counts} suspended accounts.")
I have no idea if using import sys
to change path is the best practice or not, but it seems to work.
2