diff --git a/app/db/crud.py b/app/db/crud.py
@@ -232,7 +232,7 @@ def get_users(
data_limit_reached: bool | None = None,
enabled: bool | None = None,
) -> Union[List[User], Tuple[List[User], int]]:
- query = db.query(User)
+ query = db.query(User).filter(User.removed == False)
if usernames:
if len(usernames) == 1:
@@ -382,7 +382,8 @@ def create_user(
def remove_user(db: Session, dbuser: User):
- db.delete(dbuser)
+ dbuser.removed = True
+ dbuser.activated = False
# db.query(User).filter_by(id=user_id).delete()
db.commit()
diff --git a/app/db/migrations/versions/b0357faf51c8_add_removed_to_users.py b/app/db/migrations/versions/b0357faf51c8_add_removed_to_users.py
@@ -0,0 +1,37 @@
+"""add removed to users for soft delete
+
+Revision ID: b0357faf51c8
+Revises: 3acfdeb79b78
+Create Date: 2024-07-14 19:58:54.430547
+
+"""
+
+import sqlalchemy as sa
+from alembic import op
+
+# revision identifiers, used by Alembic.
+revision = "b0357faf51c8"
+down_revision = "3acfdeb79b78"
+branch_labels = None
+depends_on = None
+
+
+def upgrade() -> None:
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.add_column(
+ "users",
+ sa.Column(
+ "removed",
+ sa.Boolean(),
+ server_default=sa.sql.false(),
+ nullable=False,
+ ),
+ )
+
+ # ### end Alembic commands ###
+
+
+def downgrade() -> None:
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.drop_column("users", "removed")
+ # ### end Alembic commands ###
diff --git a/app/db/models.py b/app/db/models.py
@@ -153,6 +153,12 @@ class User(Base):
default=True,
server_default=sqlalchemy.sql.true(),
)
+ removed = Column(
+ Boolean,
+ nullable=False,
+ default=False,
+ server_default=sqlalchemy.sql.false(),
+ )
services = relationship(
"Service",
secondary=users_services,
@@ -237,12 +243,20 @@ class User(Base):
@hybrid_property
def is_active(self):
return (
- self.enabled and not self.expired and not self.data_limit_reached
+ self.enabled
+ and not self.expired
+ and not self.data_limit_reached
+ and not self.removed
)
@is_active.expression
def is_active(cls):
- return and_(cls.enabled == True, ~cls.expired, ~cls.data_limit_reached)
+ return and_(
+ cls.enabled == True,
+ ~cls.expired,
+ ~cls.data_limit_reached,
+ ~cls.removed,
+ )
@property
def status(self):
diff --git a/app/routes/user.py b/app/routes/user.py
@@ -70,7 +70,7 @@ def get_users(
"""
dbadmin = crud.get_admin(db, admin.username)
- query = db.query(User)
+ query = db.query(User).filter(User.removed == False)
admin = dbadmin if not admin.is_sudo else None
@@ -171,14 +171,13 @@ async def delete_expired(
expired_users = [
user
for user in db_users
- if user.expire is not None and user.expire <= expiration_threshold
+ if user.expire_date is not None
+ and user.expire_date <= expiration_threshold
]
if not expired_users:
raise HTTPException(status_code=404, detail="No expired user found.")
for db_user in expired_users:
- if db_user.activated and not db_user.is_active:
- marznode.operations.update_user(db_user)
crud.remove_user(db, db_user)
asyncio.ensure_future(