users.py 7.28 KB
Newer Older
Timothy J. Baek's avatar
Timothy J. Baek committed
1
from fastapi import Response, Request
Timothy J. Baek's avatar
Timothy J. Baek committed
2
3
from fastapi import Depends, FastAPI, HTTPException, status
from datetime import datetime, timedelta
Michael Poluektov's avatar
Michael Poluektov committed
4
from typing import Union, Optional
Timothy J. Baek's avatar
Timothy J. Baek committed
5
6
7
8
9

from fastapi import APIRouter
from pydantic import BaseModel
import time
import uuid
10
import logging
Timothy J. Baek's avatar
Timothy J. Baek committed
11

12
13
14
15
16
17
18
from apps.webui.models.users import (
    UserModel,
    UserUpdateForm,
    UserRoleUpdateForm,
    UserSettings,
    Users,
)
19
20
from apps.webui.models.auths import Auths
from apps.webui.models.chats import Chats
Timothy J. Baek's avatar
Timothy J. Baek committed
21

22
23
24
25
26
27
from utils.utils import (
    get_verified_user,
    get_password_hash,
    get_current_user,
    get_admin_user,
)
Timothy J. Baek's avatar
Timothy J. Baek committed
28
29
from constants import ERROR_MESSAGES

30
from config import SRC_LOG_LEVELS
Timothy J. Baek's avatar
Timothy J. Baek committed
31

32
33
34
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["MODELS"])

Timothy J. Baek's avatar
Timothy J. Baek committed
35
36
37
38
39
40
41
router = APIRouter()

############################
# GetUsers
############################


Michael Poluektov's avatar
Michael Poluektov committed
42
@router.get("/", response_model=list[UserModel])
43
async def get_users(skip: int = 0, limit: int = 50, user=Depends(get_admin_user)):
44
    return Users.get_users(skip, limit)
Timothy J. Baek's avatar
Timothy J. Baek committed
45
46


Timothy J. Baek's avatar
Timothy J. Baek committed
47
48
49
50
51
52
53
############################
# User Permissions
############################


@router.get("/permissions/user")
async def get_user_permissions(request: Request, user=Depends(get_admin_user)):
54
    return request.app.state.config.USER_PERMISSIONS
Timothy J. Baek's avatar
Timothy J. Baek committed
55
56
57
58
59
60


@router.post("/permissions/user")
async def update_user_permissions(
    request: Request, form_data: dict, user=Depends(get_admin_user)
):
61
62
    request.app.state.config.USER_PERMISSIONS = form_data
    return request.app.state.config.USER_PERMISSIONS
Timothy J. Baek's avatar
Timothy J. Baek committed
63
64


Timothy J. Baek's avatar
Timothy J. Baek committed
65
66
67
68
69
70
############################
# UpdateUserRole
############################


@router.post("/update/role", response_model=Optional[UserModel])
71
async def update_user_role(form_data: UserRoleUpdateForm, user=Depends(get_admin_user)):
Timothy J. Baek's avatar
Timothy J. Baek committed
72

73
74
    if user.id != form_data.id and form_data.id != Users.get_first_user().id:
        return Users.update_user_role_by_id(form_data.id, form_data.role)
75
76
77
78
79

    raise HTTPException(
        status_code=status.HTTP_403_FORBIDDEN,
        detail=ERROR_MESSAGES.ACTION_PROHIBITED,
    )
Timothy J. Baek's avatar
Timothy J. Baek committed
80
81


82
83
84
85
86
87
############################
# GetUserSettingsBySessionUser
############################


@router.get("/user/settings", response_model=Optional[UserSettings])
88
async def get_user_settings_by_session_user(user=Depends(get_verified_user)):
89
    user = Users.get_user_by_id(user.id)
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
    if user:
        return user.settings
    else:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=ERROR_MESSAGES.USER_NOT_FOUND,
        )


############################
# UpdateUserSettingsBySessionUser
############################


@router.post("/user/settings/update", response_model=UserSettings)
async def update_user_settings_by_session_user(
106
    form_data: UserSettings, user=Depends(get_verified_user)
107
):
108
    user = Users.update_user_by_id(user.id, {"settings": form_data.model_dump()})
109
110
111
112
113
114
115
116
117
    if user:
        return user.settings
    else:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=ERROR_MESSAGES.USER_NOT_FOUND,
        )


Timothy J. Baek's avatar
Timothy J. Baek committed
118
119
120
121
122
123
############################
# GetUserInfoBySessionUser
############################


@router.get("/user/info", response_model=Optional[dict])
124
async def get_user_info_by_session_user(user=Depends(get_verified_user)):
125
    user = Users.get_user_by_id(user.id)
Timothy J. Baek's avatar
Timothy J. Baek committed
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
    if user:
        return user.info
    else:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=ERROR_MESSAGES.USER_NOT_FOUND,
        )


############################
# UpdateUserInfoBySessionUser
############################


@router.post("/user/info/update", response_model=Optional[dict])
141
async def update_user_info_by_session_user(
142
    form_data: dict, user=Depends(get_verified_user)
Timothy J. Baek's avatar
Timothy J. Baek committed
143
):
144
    user = Users.get_user_by_id(user.id)
Timothy J. Baek's avatar
Timothy J. Baek committed
145
146
147
148
    if user:
        if user.info is None:
            user.info = {}

149
        user = Users.update_user_by_id(user.id, {"info": {**user.info, **form_data}})
Timothy J. Baek's avatar
Timothy J. Baek committed
150
151
152
153
154
155
156
157
158
159
160
161
162
163
        if user:
            return user.info
        else:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=ERROR_MESSAGES.USER_NOT_FOUND,
            )
    else:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=ERROR_MESSAGES.USER_NOT_FOUND,
        )


164
165
166
167
168
169
170
171
172
173
174
############################
# GetUserById
############################


class UserResponse(BaseModel):
    name: str
    profile_image_url: str


@router.get("/{user_id}", response_model=UserResponse)
175
async def get_user_by_id(user_id: str, user=Depends(get_verified_user)):
176

177
178
    # Check if user_id is a shared chat
    # If it is, get the user_id from the chat
Timothy J. Baek's avatar
Timothy J. Baek committed
179
180
    if user_id.startswith("shared-"):
        chat_id = user_id.replace("shared-", "")
181
        chat = Chats.get_chat_by_id(chat_id)
Timothy J. Baek's avatar
Timothy J. Baek committed
182
183
184
185
186
187
188
189
        if chat:
            user_id = chat.user_id
        else:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=ERROR_MESSAGES.USER_NOT_FOUND,
            )

190
    user = Users.get_user_by_id(user_id)
191
192
193
194
195
196
197
198
199
200

    if user:
        return UserResponse(name=user.name, profile_image_url=user.profile_image_url)
    else:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=ERROR_MESSAGES.USER_NOT_FOUND,
        )


Timothy J. Baek's avatar
Timothy J. Baek committed
201
############################
Timothy J. Baek's avatar
Timothy J. Baek committed
202
# UpdateUserById
Timothy J. Baek's avatar
Timothy J. Baek committed
203
204
205
############################


Timothy J. Baek's avatar
Timothy J. Baek committed
206
207
@router.post("/{user_id}/update", response_model=Optional[UserModel])
async def update_user_by_id(
208
209
210
    user_id: str,
    form_data: UserUpdateForm,
    session_user=Depends(get_admin_user),
Timothy J. Baek's avatar
Timothy J. Baek committed
211
):
212
    user = Users.get_user_by_id(user_id)
Timothy J. Baek's avatar
Timothy J. Baek committed
213
214

    if user:
Timothy J. Baek's avatar
Timothy J. Baek committed
215
        if form_data.email.lower() != user.email:
216
            email_user = Users.get_user_by_email(form_data.email.lower())
Timothy J. Baek's avatar
Timothy J. Baek committed
217
218
219
220
221
222
223
224
            if email_user:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail=ERROR_MESSAGES.EMAIL_TAKEN,
                )

        if form_data.password:
            hashed = get_password_hash(form_data.password)
225
            log.debug(f"hashed: {hashed}")
226
            Auths.update_user_password_by_id(user_id, hashed)
Timothy J. Baek's avatar
Timothy J. Baek committed
227

228
        Auths.update_email_by_id(user_id, form_data.email.lower())
Timothy J. Baek's avatar
Timothy J. Baek committed
229
230
231
232
        updated_user = Users.update_user_by_id(
            user_id,
            {
                "name": form_data.name,
Timothy J. Baek's avatar
Timothy J. Baek committed
233
                "email": form_data.email.lower(),
Timothy J. Baek's avatar
Timothy J. Baek committed
234
235
236
237
238
239
240
                "profile_image_url": form_data.profile_image_url,
            },
        )

        if updated_user:
            return updated_user

Timothy J. Baek's avatar
Timothy J. Baek committed
241
        raise HTTPException(
Timothy J. Baek's avatar
Timothy J. Baek committed
242
            status_code=status.HTTP_400_BAD_REQUEST,
243
            detail=ERROR_MESSAGES.DEFAULT(),
Timothy J. Baek's avatar
Timothy J. Baek committed
244
        )
245

246
247
248
249
250
    raise HTTPException(
        status_code=status.HTTP_400_BAD_REQUEST,
        detail=ERROR_MESSAGES.USER_NOT_FOUND,
    )

251
252

############################
Timothy J. Baek's avatar
Timothy J. Baek committed
253
# DeleteUserById
254
255
256
257
############################


@router.delete("/{user_id}", response_model=bool)
258
async def delete_user_by_id(user_id: str, user=Depends(get_admin_user)):
259
    if user.id != user_id:
260
        result = Auths.delete_auth_by_id(user_id)
261
262
263
264

        if result:
            return True

265
        raise HTTPException(
266
267
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=ERROR_MESSAGES.DELETE_USER_ERROR,
268
        )
269
270
271
272
273

    raise HTTPException(
        status_code=status.HTTP_403_FORBIDDEN,
        detail=ERROR_MESSAGES.ACTION_PROHIBITED,
    )