瀏覽代碼

feat: toggle signup enable from admin panel

Timothy J. Baek 1 年之前
父節點
當前提交
bb5bf3964e

+ 0 - 1
Dockerfile

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

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

@@ -8,6 +8,8 @@ app = FastAPI()
 
 
 origins = ["*"]
 origins = ["*"]
 
 
+app.state.ENABLE_SIGNUP = True
+
 app.add_middleware(
 app.add_middleware(
     CORSMiddleware,
     CORSMiddleware,
     allow_origins=origins,
     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 fastapi import Depends, FastAPI, HTTPException, status
 from datetime import datetime, timedelta
 from datetime import datetime, timedelta
 from typing import List, Union
 from typing import List, Union
@@ -93,31 +93,62 @@ async def signin(form_data: SigninForm):
 
 
 
 
 @router.post("/signup", response_model=SigninResponse)
 @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:
     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 utils.utils import get_current_user
 from constants import ERROR_MESSAGES
 from constants import ERROR_MESSAGES
 
 
+
 router = APIRouter()
 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;
 	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 toast from 'svelte-french-toast';
 
 
 	import { updateUserRole, getUsers, deleteUserById } from '$lib/apis/users';
 	import { updateUserRole, getUsers, deleteUserById } from '$lib/apis/users';
+	import { getSignUpEnabledStatus, toggleSignUpEnabledStatus } from '$lib/apis/auths';
 
 
 	let loaded = false;
 	let loaded = false;
 	let users = [];
 	let users = [];
 
 
+	let signUpEnabled = true;
+
 	const updateRoleHandler = async (id, role) => {
 	const updateRoleHandler = async (id, role) => {
 		const res = await updateUserRole(localStorage.token, id, role).catch((error) => {
 		const res = await updateUserRole(localStorage.token, id, role).catch((error) => {
 			toast.error(error);
 			toast.error(error);
@@ -32,11 +35,17 @@
 		}
 		}
 	};
 	};
 
 
+	const toggleSignUpEnabled = async () => {
+		signUpEnabled = await toggleSignUpEnabledStatus(localStorage.token);
+	};
+
 	onMount(async () => {
 	onMount(async () => {
 		if ($user?.role !== 'admin') {
 		if ($user?.role !== 'admin') {
 			await goto('/');
 			await goto('/');
 		} else {
 		} else {
 			users = await getUsers(localStorage.token);
 			users = await getUsers(localStorage.token);
+
+			signUpEnabled = await getSignUpEnabledStatus(localStorage.token);
 		}
 		}
 		loaded = true;
 		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="w-full max-w-3xl px-10 md:px-16 min-h-screen flex flex-col">
 			<div class="py-10 w-full">
 			<div class="py-10 w-full">
 				<div class=" flex flex-col justify-center">
 				<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">
 					<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.
 						Click on the user role cell in the table to change a user's role.
 					</div>
 					</div>