main
py 257 lines 7.87 KB
Raw
1 from typing import List
2
3 from fastapi import HTTPException
4 from loguru import logger
5
6 # ! New with Async
7 from sqlalchemy.ext.asyncio import AsyncSession
8 from sqlalchemy.orm import Session
9 from sqlalchemy.orm import selectinload
10 from sqlmodel import select
11
12 from app.auth.models.users import Password
13 from app.auth.models.users import Role
14 from app.auth.models.users import User
15 from app.auth.models.users import UserCustomerAccess
16 from app.db.db_session import async_engine
17
18 passwords_in_memory = {}
19
20
21 def select_all_users_sync(session: Session) -> List[User]:
22 """
23 Retrieves all Users from the database with their role information.
24
25 Args:
26 session: The database session to use for the query.
27
28 Returns:
29 List[User]: A list of all Users in the database with role information loaded.
30 """
31 result = session.exec(select(User).options(selectinload(User.role)))
32 return result.all()
33
34
35 async def select_all_users():
36 """
37 Async version: Retrieves all Users from the database with their role information.
38
39 Returns:
40 List[User]: A list of all Users in the database with role information loaded.
41 """
42 async with AsyncSession(async_engine) as session:
43 statement = select(User).options(selectinload(User.role))
44 result = await session.execute(statement)
45 return result.scalars().all()
46
47
48 async def find_user(name: str):
49 """
50 Find a user by their username.
51
52 Args:
53 name (str): The username of the user to find.
54
55 Returns:
56 User: The user object if found, None otherwise.
57 """
58 try:
59 async with AsyncSession(async_engine) as session:
60 statement = select(User).where(User.username == name)
61 result = await session.execute(statement)
62 return result.scalars().first()
63 except Exception as e:
64 logger.error(f"Error: {e}")
65 return None
66
67
68 async def get_role(name: str):
69 """
70 Retrieve the role name for a given user name.
71
72 Args:
73 name (str): The name of the user.
74
75 Returns:
76 str: The name of the user's role.
77 """
78 async with AsyncSession(async_engine) as session:
79 user = await find_user(name)
80 if user:
81 statement = select(Role).where(Role.id == user.role_id)
82 result = await session.execute(statement)
83 role = result.scalars().first()
84 return role.name
85
86
87 async def check_admin_user_exists(session: AsyncSession) -> bool:
88 """
89 Check if admin user exists in the database
90 If not, return False
91
92 :param session: The database session
93 :type session: AsyncSession
94 :return: True if admin user exists, False otherwise
95 :rtype: bool
96 """
97 statement = select(User).where(User.username == "admin")
98 result = await session.execute(statement)
99 user = result.scalars().first()
100 return user is not None
101
102
103 async def check_scheduler_user_exists(session: AsyncSession) -> bool:
104 """
105 Check if scheduler user exists in the database
106 If not, return False
107
108 :param session: The database session to use for the query
109 :type session: AsyncSession
110 :return: True if the scheduler user exists, False otherwise
111 :rtype: bool
112 """
113 statement = select(User).where(User.username == "scheduler")
114 result = await session.execute(statement)
115 user = result.scalars().first()
116 return user is not None
117
118
119 async def create_admin_user(session: AsyncSession):
120 """
121 Check if the admin user exists in the database.
122 If not, create the admin user.
123
124 Parameters:
125 - session: The database session to use for querying and committing changes.
126
127 Returns:
128 - None
129 """
130 if not await check_admin_user_exists(
131 session,
132 ): # The check function needs to be passed the session as well
133 # Create the admin user
134 password_model = Password.generate(length=24)
135 admin_user = User(
136 username="admin",
137 password=password_model.hashed, # Assuming you store the hashed password
138 email="admin@admin.com",
139 role_id=1, # Make sure the role_id corresponds to the admin role in your DB
140 )
141 session.add(admin_user)
142 admin_username = admin_user.username
143 await session.commit()
144 logger.info(f"Added new admin user with username: {admin_username}")
145 logger.info(f"Admin user password: {password_model}")
146 else:
147 logger.info("Admin user already exists.")
148 return
149
150
151 async def create_scheduler_user(session: AsyncSession):
152 """
153 Check if the scheduler user exists in the database.
154 If not, create the scheduler user.
155
156 Parameters:
157 - session: The database session to use for querying and committing changes.
158
159 Returns:
160 - None
161 """
162 if not await check_scheduler_user_exists(
163 session,
164 ): # The check function needs to be passed the session as well
165 # Create the scheduler user
166 password_model = Password.generate(length=12)
167 scheduler_user = User(
168 username="scheduler",
169 password=password_model.hashed, # Assuming you store the hashed password
170 email="scheduler@scheduler.com",
171 role_id=3, # Make sure the role_id corresponds to the scheduler role in your DB
172 )
173 session.add(scheduler_user)
174 scheduler_username = scheduler_user.username
175 password_plain = password_model.plain
176 await session.commit()
177 logger.info(f"Added new scheduler user with username: {scheduler_username}")
178 logger.info(f"Scheduler user password: {password_plain}")
179 passwords_in_memory["scheduler"] = password_plain
180 else:
181 logger.info("Scheduler user already exists.")
182 return
183
184
185 async def remove_scheduler_user(session: AsyncSession):
186 """
187 Check if the scheduler user exists in the database.
188 If so, remove the scheduler user.
189
190 Args:
191 session (AsyncSession): The async session object used for database operations.
192
193 Returns:
194 None
195 """
196 # Check if the scheduler user exists
197 statement = select(User).where(User.username == "scheduler")
198 result = await session.execute(statement)
199 scheduler_user = result.scalars().first()
200
201 if scheduler_user:
202 # Remove the scheduler user
203 await session.delete(scheduler_user)
204 await session.commit() # This is awaited because commit is async
205 logger.info("Scheduler user removed.")
206 else:
207 logger.info("Scheduler user does not exist.")
208
209
210 def get_scheduler_password():
211 """
212 Retrieve the scheduler user's unhashed password from memory.
213
214 Returns:
215 str: The unhashed password of the scheduler user.
216 """
217 return passwords_in_memory.get("scheduler")
218
219
220 async def delete_user(user_id: int, session: AsyncSession):
221 """
222 Delete a user from the database.
223
224 Args:
225 user_id (int): The ID of the user to delete.
226 session (AsyncSession): The database session to use for the operation.
227
228 Returns:
229 None
230 """
231 # First check if user exists
232 statement = select(User).where(User.id == user_id)
233 result = await session.execute(statement)
234 user = result.scalars().first()
235
236 if not user:
237 raise HTTPException(status_code=404, detail="User not found.")
238
239 if user.id == 1:
240 raise HTTPException(status_code=403, detail="Cannot delete admin user")
241
242 # Database operations in try block
243 try:
244 # Delete related customer access records first
245 from sqlalchemy import delete as sql_delete
246
247 await session.execute(sql_delete(UserCustomerAccess).where(UserCustomerAccess.user_id == user_id))
248
249 await session.delete(user)
250 await session.commit()
251 logger.info(f"User with ID {user_id} deleted.")
252 except Exception as e:
253 await session.rollback()
254 logger.error(f"Error deleting user {user_id}: {str(e)}")
255 raise HTTPException(status_code=500, detail="Error deleting user")
256
257 return {"message": "User deleted successfully.", "success": True}