Browse Source

feat: toggle signup enable from admin panel

Timothy J. Baek 1 năm trước cách đây
mục cha
commit
bb5bf3964e

+ 0 - 1
Dockerfile

@@ -22,7 +22,6 @@ ARG OLLAMA_API_BASE_URL='/ollama/api'
 
 ENV ENV=prod
 ENV OLLAMA_API_BASE_URL $OLLAMA_API_BASE_URL
-ENV WEBUI_AUTH ""
 ENV WEBUI_JWT_SECRET_KEY "SECRET_KEY"
 
 WORKDIR /app

+ 2 - 0
backend/apps/web/main.py

@@ -8,6 +8,8 @@ app = FastAPI()
 
 origins = ["*"]
 
+app.state.ENABLE_SIGNUP = True
+
 app.add_middleware(
     CORSMiddleware,
     allow_origins=origins,

+ 59 - 28
backend/apps/web/routers/auths.py

@@ -1,4 +1,4 @@
-from fastapi import Response
+from fastapi import Response, Request
 from fastapi import Depends, FastAPI, HTTPException, status
 from datetime import datetime, timedelta
 from typing import List, Union
@@ -93,31 +93,62 @@ async def signin(form_data: SigninForm):
 
 
 @router.post("/signup", response_model=SigninResponse)
-async def signup(form_data: SignupForm):
-    if not Users.get_user_by_email(form_data.email.lower()):
-        try:
-            role = "admin" if Users.get_num_users() == 0 else "pending"
-            hashed = get_password_hash(form_data.password)
-            user = Auths.insert_new_auth(
-                form_data.email.lower(), hashed, form_data.name, role
-            )
-
-            if user:
-                token = create_token(data={"email": user.email})
-                # response.set_cookie(key='token', value=token, httponly=True)
-
-                return {
-                    "token": token,
-                    "token_type": "Bearer",
-                    "id": user.id,
-                    "email": user.email,
-                    "name": user.name,
-                    "role": user.role,
-                    "profile_image_url": user.profile_image_url,
-                }
-            else:
-                raise HTTPException(500, detail=ERROR_MESSAGES.CREATE_USER_ERROR)
-        except Exception as err:
-            raise HTTPException(500, detail=ERROR_MESSAGES.DEFAULT(err))
+async def signup(request: Request, form_data: SignupForm):
+    if request.app.state.ENABLE_SIGNUP:
+        if not Users.get_user_by_email(form_data.email.lower()):
+            try:
+                role = "admin" if Users.get_num_users() == 0 else "pending"
+                hashed = get_password_hash(form_data.password)
+                user = Auths.insert_new_auth(
+                    form_data.email.lower(), hashed, form_data.name, role
+                )
+
+                if user:
+                    token = create_token(data={"email": user.email})
+                    # response.set_cookie(key='token', value=token, httponly=True)
+
+                    return {
+                        "token": token,
+                        "token_type": "Bearer",
+                        "id": user.id,
+                        "email": user.email,
+                        "name": user.name,
+                        "role": user.role,
+                        "profile_image_url": user.profile_image_url,
+                    }
+                else:
+                    raise HTTPException(500, detail=ERROR_MESSAGES.CREATE_USER_ERROR)
+            except Exception as err:
+                raise HTTPException(500, detail=ERROR_MESSAGES.DEFAULT(err))
+        else:
+            raise HTTPException(400, detail=ERROR_MESSAGES.EMAIL_TAKEN)
+    else:
+        raise HTTPException(400, detail=ERROR_MESSAGES.ACCESS_PROHIBITED)
+
+
+############################
+# ToggleSignUp
+############################
+
+
+@router.get("/signup/enabled", response_model=bool)
+async def get_sign_up_status(request: Request, user=Depends(get_current_user)):
+    if user.role == "admin":
+        return request.app.state.ENABLE_SIGNUP
+    else:
+        raise HTTPException(
+            status_code=status.HTTP_403_FORBIDDEN,
+            detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
+        )
+
+
+@router.get("/signup/enabled/toggle", response_model=bool)
+async def toggle_sign_up(request: Request, user=Depends(get_current_user)):
+    if user.role == "admin":
+        request.app.state.ENABLE_SIGNUP = not request.app.state.ENABLE_SIGNUP
+        return request.app.state.ENABLE_SIGNUP
     else:
-        raise HTTPException(400, detail=ERROR_MESSAGES.EMAIL_TAKEN)
+        raise HTTPException(
+            status_code=status.HTTP_403_FORBIDDEN,
+            detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
+        )

+ 1 - 0
backend/apps/web/routers/users.py

@@ -15,6 +15,7 @@ from apps.web.models.auths import Auths
 from utils.utils import get_current_user
 from constants import ERROR_MESSAGES
 
+
 router = APIRouter()
 
 ############################

+ 54 - 0
src/lib/apis/auths/index.ts

@@ -119,3 +119,57 @@ export const updateUserPassword = async (token: string, password: string, newPas
 
 	return res;
 };
+
+export const getSignUpEnabledStatus = async (token: string) => {
+	let error = null;
+
+	const res = await fetch(`${WEBUI_API_BASE_URL}/auths/signup/enabled`, {
+		method: 'GET',
+		headers: {
+			'Content-Type': 'application/json',
+			Authorization: `Bearer ${token}`
+		}
+	})
+		.then(async (res) => {
+			if (!res.ok) throw await res.json();
+			return res.json();
+		})
+		.catch((err) => {
+			console.log(err);
+			error = err.detail;
+			return null;
+		});
+
+	if (error) {
+		throw error;
+	}
+
+	return res;
+};
+
+export const toggleSignUpEnabledStatus = async (token: string) => {
+	let error = null;
+
+	const res = await fetch(`${WEBUI_API_BASE_URL}/auths/signup/enabled/toggle`, {
+		method: 'GET',
+		headers: {
+			'Content-Type': 'application/json',
+			Authorization: `Bearer ${token}`
+		}
+	})
+		.then(async (res) => {
+			if (!res.ok) throw await res.json();
+			return res.json();
+		})
+		.catch((err) => {
+			console.log(err);
+			error = err.detail;
+			return null;
+		});
+
+	if (error) {
+		throw error;
+	}
+
+	return res;
+};

+ 55 - 1
src/routes/(app)/admin/+page.svelte

@@ -7,10 +7,13 @@
 	import toast from 'svelte-french-toast';
 
 	import { updateUserRole, getUsers, deleteUserById } from '$lib/apis/users';
+	import { getSignUpEnabledStatus, toggleSignUpEnabledStatus } from '$lib/apis/auths';
 
 	let loaded = false;
 	let users = [];
 
+	let signUpEnabled = true;
+
 	const updateRoleHandler = async (id, role) => {
 		const res = await updateUserRole(localStorage.token, id, role).catch((error) => {
 			toast.error(error);
@@ -32,11 +35,17 @@
 		}
 	};
 
+	const toggleSignUpEnabled = async () => {
+		signUpEnabled = await toggleSignUpEnabledStatus(localStorage.token);
+	};
+
 	onMount(async () => {
 		if ($user?.role !== 'admin') {
 			await goto('/');
 		} else {
 			users = await getUsers(localStorage.token);
+
+			signUpEnabled = await getSignUpEnabledStatus(localStorage.token);
 		}
 		loaded = true;
 	});
@@ -49,7 +58,52 @@
 		<div class="w-full max-w-3xl px-10 md:px-16 min-h-screen flex flex-col">
 			<div class="py-10 w-full">
 				<div class=" flex flex-col justify-center">
-					<div class=" text-2xl font-semibold">Users ({users.length})</div>
+					<div class=" flex justify-between items-center">
+						<div class=" text-2xl font-semibold">Users ({users.length})</div>
+						<div>
+							<button
+								class="flex items-center space-x-1 border border-gray-200 px-3 py-1 rounded-lg"
+								type="button"
+								on:click={() => {
+									toggleSignUpEnabled();
+								}}
+							>
+								{#if signUpEnabled}
+									<svg
+										xmlns="http://www.w3.org/2000/svg"
+										viewBox="0 0 16 16"
+										fill="currentColor"
+										class="w-4 h-4"
+									>
+										<path
+											d="M11.5 1A3.5 3.5 0 0 0 8 4.5V7H2.5A1.5 1.5 0 0 0 1 8.5v5A1.5 1.5 0 0 0 2.5 15h7a1.5 1.5 0 0 0 1.5-1.5v-5A1.5 1.5 0 0 0 9.5 7V4.5a2 2 0 1 1 4 0v1.75a.75.75 0 0 0 1.5 0V4.5A3.5 3.5 0 0 0 11.5 1Z"
+										/>
+									</svg>
+
+									<div class=" text-xs">
+										New Sign Up <span class=" font-semibold">Enabled</span>
+									</div>
+								{:else}
+									<svg
+										xmlns="http://www.w3.org/2000/svg"
+										viewBox="0 0 16 16"
+										fill="currentColor"
+										class="w-4 h-4"
+									>
+										<path
+											fill-rule="evenodd"
+											d="M8 1a3.5 3.5 0 0 0-3.5 3.5V7A1.5 1.5 0 0 0 3 8.5v5A1.5 1.5 0 0 0 4.5 15h7a1.5 1.5 0 0 0 1.5-1.5v-5A1.5 1.5 0 0 0 11.5 7V4.5A3.5 3.5 0 0 0 8 1Zm2 6V4.5a2 2 0 1 0-4 0V7h4Z"
+											clip-rule="evenodd"
+										/>
+									</svg>
+
+									<div class=" text-xs">
+										New Sign Up <span class=" font-semibold">Disabled</span>
+									</div>
+								{/if}
+							</button>
+						</div>
+					</div>
 					<div class=" text-gray-500 text-xs font-medium mt-1">
 						Click on the user role cell in the table to change a user's role.
 					</div>