mirror of
https://github.com/open-webui/open-webui
synced 2025-06-23 02:16:52 +00:00
feat: admin details in account pending overlay
This commit is contained in:
parent
61867c1545
commit
25336f85f3
@ -14,6 +14,8 @@ from apps.webui.routers import (
|
|||||||
)
|
)
|
||||||
from config import (
|
from config import (
|
||||||
WEBUI_BUILD_HASH,
|
WEBUI_BUILD_HASH,
|
||||||
|
SHOW_ADMIN_DETAILS,
|
||||||
|
ADMIN_EMAIL,
|
||||||
WEBUI_AUTH,
|
WEBUI_AUTH,
|
||||||
DEFAULT_MODELS,
|
DEFAULT_MODELS,
|
||||||
DEFAULT_PROMPT_SUGGESTIONS,
|
DEFAULT_PROMPT_SUGGESTIONS,
|
||||||
@ -37,6 +39,11 @@ app.state.config = AppConfig()
|
|||||||
app.state.config.ENABLE_SIGNUP = ENABLE_SIGNUP
|
app.state.config.ENABLE_SIGNUP = ENABLE_SIGNUP
|
||||||
app.state.config.JWT_EXPIRES_IN = JWT_EXPIRES_IN
|
app.state.config.JWT_EXPIRES_IN = JWT_EXPIRES_IN
|
||||||
|
|
||||||
|
|
||||||
|
app.state.config.SHOW_ADMIN_DETAILS = SHOW_ADMIN_DETAILS
|
||||||
|
app.state.config.ADMIN_EMAIL = ADMIN_EMAIL
|
||||||
|
|
||||||
|
|
||||||
app.state.config.DEFAULT_MODELS = DEFAULT_MODELS
|
app.state.config.DEFAULT_MODELS = DEFAULT_MODELS
|
||||||
app.state.config.DEFAULT_PROMPT_SUGGESTIONS = DEFAULT_PROMPT_SUGGESTIONS
|
app.state.config.DEFAULT_PROMPT_SUGGESTIONS = DEFAULT_PROMPT_SUGGESTIONS
|
||||||
app.state.config.DEFAULT_USER_ROLE = DEFAULT_USER_ROLE
|
app.state.config.DEFAULT_USER_ROLE = DEFAULT_USER_ROLE
|
||||||
|
@ -269,73 +269,88 @@ async def add_user(form_data: AddUserForm, user=Depends(get_admin_user)):
|
|||||||
raise HTTPException(500, detail=ERROR_MESSAGES.DEFAULT(err))
|
raise HTTPException(500, detail=ERROR_MESSAGES.DEFAULT(err))
|
||||||
|
|
||||||
|
|
||||||
|
############################
|
||||||
|
# GetAdminDetails
|
||||||
|
############################
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/admin/details")
|
||||||
|
async def get_admin_details(request: Request, user=Depends(get_current_user)):
|
||||||
|
if request.app.state.config.SHOW_ADMIN_DETAILS:
|
||||||
|
admin_email = request.app.state.config.ADMIN_EMAIL
|
||||||
|
admin_name = None
|
||||||
|
|
||||||
|
print(admin_email, admin_name)
|
||||||
|
|
||||||
|
if admin_email:
|
||||||
|
admin = Users.get_user_by_email(admin_email)
|
||||||
|
if admin:
|
||||||
|
admin_name = admin.name
|
||||||
|
else:
|
||||||
|
admin = Users.get_first_user()
|
||||||
|
if admin:
|
||||||
|
admin_email = admin.email
|
||||||
|
admin_name = admin.name
|
||||||
|
|
||||||
|
return {
|
||||||
|
"name": admin_name,
|
||||||
|
"email": admin_email,
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
raise HTTPException(400, detail=ERROR_MESSAGES.ACTION_PROHIBITED)
|
||||||
|
|
||||||
|
|
||||||
############################
|
############################
|
||||||
# ToggleSignUp
|
# ToggleSignUp
|
||||||
############################
|
############################
|
||||||
|
|
||||||
|
|
||||||
@router.get("/signup/enabled", response_model=bool)
|
@router.get("/admin/config")
|
||||||
async def get_sign_up_status(request: Request, user=Depends(get_admin_user)):
|
async def get_admin_config(request: Request, user=Depends(get_admin_user)):
|
||||||
return request.app.state.config.ENABLE_SIGNUP
|
return {
|
||||||
|
"SHOW_ADMIN_DETAILS": request.app.state.config.SHOW_ADMIN_DETAILS,
|
||||||
|
"ENABLE_SIGNUP": request.app.state.config.ENABLE_SIGNUP,
|
||||||
|
"DEFAULT_USER_ROLE": request.app.state.config.DEFAULT_USER_ROLE,
|
||||||
|
"JWT_EXPIRES_IN": request.app.state.config.JWT_EXPIRES_IN,
|
||||||
|
"ENABLE_COMMUNITY_SHARING": request.app.state.config.ENABLE_COMMUNITY_SHARING,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@router.get("/signup/enabled/toggle", response_model=bool)
|
class AdminConfig(BaseModel):
|
||||||
async def toggle_sign_up(request: Request, user=Depends(get_admin_user)):
|
SHOW_ADMIN_DETAILS: bool
|
||||||
request.app.state.config.ENABLE_SIGNUP = not request.app.state.config.ENABLE_SIGNUP
|
ENABLE_SIGNUP: bool
|
||||||
return request.app.state.config.ENABLE_SIGNUP
|
DEFAULT_USER_ROLE: str
|
||||||
|
JWT_EXPIRES_IN: str
|
||||||
|
ENABLE_COMMUNITY_SHARING: bool
|
||||||
|
|
||||||
|
|
||||||
############################
|
@router.post("/admin/config")
|
||||||
# Default User Role
|
async def update_admin_config(
|
||||||
############################
|
request: Request, form_data: AdminConfig, user=Depends(get_admin_user)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/signup/user/role")
|
|
||||||
async def get_default_user_role(request: Request, user=Depends(get_admin_user)):
|
|
||||||
return request.app.state.config.DEFAULT_USER_ROLE
|
|
||||||
|
|
||||||
|
|
||||||
class UpdateRoleForm(BaseModel):
|
|
||||||
role: str
|
|
||||||
|
|
||||||
|
|
||||||
@router.post("/signup/user/role")
|
|
||||||
async def update_default_user_role(
|
|
||||||
request: Request, form_data: UpdateRoleForm, user=Depends(get_admin_user)
|
|
||||||
):
|
):
|
||||||
if form_data.role in ["pending", "user", "admin"]:
|
request.app.state.config.SHOW_ADMIN_DETAILS = form_data.SHOW_ADMIN_DETAILS
|
||||||
request.app.state.config.DEFAULT_USER_ROLE = form_data.role
|
request.app.state.config.ENABLE_SIGNUP = form_data.ENABLE_SIGNUP
|
||||||
return request.app.state.config.DEFAULT_USER_ROLE
|
|
||||||
|
|
||||||
|
if form_data.DEFAULT_USER_ROLE in ["pending", "user", "admin"]:
|
||||||
|
request.app.state.config.DEFAULT_USER_ROLE = form_data.DEFAULT_USER_ROLE
|
||||||
|
|
||||||
############################
|
|
||||||
# JWT Expiration
|
|
||||||
############################
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/token/expires")
|
|
||||||
async def get_token_expires_duration(request: Request, user=Depends(get_admin_user)):
|
|
||||||
return request.app.state.config.JWT_EXPIRES_IN
|
|
||||||
|
|
||||||
|
|
||||||
class UpdateJWTExpiresDurationForm(BaseModel):
|
|
||||||
duration: str
|
|
||||||
|
|
||||||
|
|
||||||
@router.post("/token/expires/update")
|
|
||||||
async def update_token_expires_duration(
|
|
||||||
request: Request,
|
|
||||||
form_data: UpdateJWTExpiresDurationForm,
|
|
||||||
user=Depends(get_admin_user),
|
|
||||||
):
|
|
||||||
pattern = r"^(-1|0|(-?\d+(\.\d+)?)(ms|s|m|h|d|w))$"
|
pattern = r"^(-1|0|(-?\d+(\.\d+)?)(ms|s|m|h|d|w))$"
|
||||||
|
|
||||||
# Check if the input string matches the pattern
|
# Check if the input string matches the pattern
|
||||||
if re.match(pattern, form_data.duration):
|
if re.match(pattern, form_data.JWT_EXPIRES_IN):
|
||||||
request.app.state.config.JWT_EXPIRES_IN = form_data.duration
|
request.app.state.config.JWT_EXPIRES_IN = form_data.JWT_EXPIRES_IN
|
||||||
return request.app.state.config.JWT_EXPIRES_IN
|
|
||||||
else:
|
request.app.state.config.ENABLE_COMMUNITY_SHARING = (
|
||||||
return request.app.state.config.JWT_EXPIRES_IN
|
form_data.ENABLE_COMMUNITY_SHARING
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"SHOW_ADMIN_DETAILS": request.app.state.config.SHOW_ADMIN_DETAILS,
|
||||||
|
"ENABLE_SIGNUP": request.app.state.config.ENABLE_SIGNUP,
|
||||||
|
"DEFAULT_USER_ROLE": request.app.state.config.DEFAULT_USER_ROLE,
|
||||||
|
"JWT_EXPIRES_IN": request.app.state.config.JWT_EXPIRES_IN,
|
||||||
|
"ENABLE_COMMUNITY_SHARING": request.app.state.config.ENABLE_COMMUNITY_SHARING,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
############################
|
############################
|
||||||
|
@ -19,7 +19,12 @@ from apps.webui.models.users import (
|
|||||||
from apps.webui.models.auths import Auths
|
from apps.webui.models.auths import Auths
|
||||||
from apps.webui.models.chats import Chats
|
from apps.webui.models.chats import Chats
|
||||||
|
|
||||||
from utils.utils import get_verified_user, get_password_hash, get_admin_user
|
from utils.utils import (
|
||||||
|
get_verified_user,
|
||||||
|
get_password_hash,
|
||||||
|
get_current_user,
|
||||||
|
get_admin_user,
|
||||||
|
)
|
||||||
from constants import ERROR_MESSAGES
|
from constants import ERROR_MESSAGES
|
||||||
|
|
||||||
from config import SRC_LOG_LEVELS
|
from config import SRC_LOG_LEVELS
|
||||||
|
@ -601,6 +601,20 @@ WEBUI_BANNERS = PersistentConfig(
|
|||||||
[BannerModel(**banner) for banner in json.loads("[]")],
|
[BannerModel(**banner) for banner in json.loads("[]")],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
SHOW_ADMIN_DETAILS = PersistentConfig(
|
||||||
|
"SHOW_ADMIN_DETAILS",
|
||||||
|
"auth.admin.show",
|
||||||
|
os.environ.get("SHOW_ADMIN_DETAILS", "true").lower() == "true",
|
||||||
|
)
|
||||||
|
|
||||||
|
ADMIN_EMAIL = PersistentConfig(
|
||||||
|
"ADMIN_EMAIL",
|
||||||
|
"auth.admin.email",
|
||||||
|
os.environ.get("ADMIN_EMAIL", None),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
####################################
|
####################################
|
||||||
# WEBUI_SECRET_KEY
|
# WEBUI_SECRET_KEY
|
||||||
####################################
|
####################################
|
||||||
|
@ -879,23 +879,7 @@ class UrlForm(BaseModel):
|
|||||||
async def update_webhook_url(form_data: UrlForm, user=Depends(get_admin_user)):
|
async def update_webhook_url(form_data: UrlForm, user=Depends(get_admin_user)):
|
||||||
app.state.config.WEBHOOK_URL = form_data.url
|
app.state.config.WEBHOOK_URL = form_data.url
|
||||||
webui_app.state.WEBHOOK_URL = app.state.config.WEBHOOK_URL
|
webui_app.state.WEBHOOK_URL = app.state.config.WEBHOOK_URL
|
||||||
|
return {"url": app.state.config.WEBHOOK_URL}
|
||||||
return {
|
|
||||||
"url": app.state.config.WEBHOOK_URL,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("/api/community_sharing", response_model=bool)
|
|
||||||
async def get_community_sharing_status(request: Request, user=Depends(get_admin_user)):
|
|
||||||
return webui_app.state.config.ENABLE_COMMUNITY_SHARING
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("/api/community_sharing/toggle", response_model=bool)
|
|
||||||
async def toggle_community_sharing(request: Request, user=Depends(get_admin_user)):
|
|
||||||
webui_app.state.config.ENABLE_COMMUNITY_SHARING = (
|
|
||||||
not webui_app.state.config.ENABLE_COMMUNITY_SHARING
|
|
||||||
)
|
|
||||||
return webui_app.state.config.ENABLE_COMMUNITY_SHARING
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("/api/version")
|
@app.get("/api/version")
|
||||||
|
@ -1,5 +1,87 @@
|
|||||||
import { WEBUI_API_BASE_URL } from '$lib/constants';
|
import { WEBUI_API_BASE_URL } from '$lib/constants';
|
||||||
|
|
||||||
|
export const getAdminDetails = async (token: string) => {
|
||||||
|
let error = null;
|
||||||
|
|
||||||
|
const res = await fetch(`${WEBUI_API_BASE_URL}/auths/admin/details`, {
|
||||||
|
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 getAdminConfig = async (token: string) => {
|
||||||
|
let error = null;
|
||||||
|
|
||||||
|
const res = await fetch(`${WEBUI_API_BASE_URL}/auths/admin/config`, {
|
||||||
|
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 updateAdminConfig = async (token: string, body: object) => {
|
||||||
|
let error = null;
|
||||||
|
|
||||||
|
const res = await fetch(`${WEBUI_API_BASE_URL}/auths/admin/config`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
Authorization: `Bearer ${token}`
|
||||||
|
},
|
||||||
|
body: JSON.stringify(body)
|
||||||
|
})
|
||||||
|
.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 getSessionUser = async (token: string) => {
|
export const getSessionUser = async (token: string) => {
|
||||||
let error = null;
|
let error = null;
|
||||||
|
|
||||||
|
@ -6,61 +6,44 @@
|
|||||||
updateWebhookUrl
|
updateWebhookUrl
|
||||||
} from '$lib/apis';
|
} from '$lib/apis';
|
||||||
import {
|
import {
|
||||||
|
getAdminConfig,
|
||||||
getDefaultUserRole,
|
getDefaultUserRole,
|
||||||
getJWTExpiresDuration,
|
getJWTExpiresDuration,
|
||||||
getSignUpEnabledStatus,
|
getSignUpEnabledStatus,
|
||||||
toggleSignUpEnabledStatus,
|
toggleSignUpEnabledStatus,
|
||||||
|
updateAdminConfig,
|
||||||
updateDefaultUserRole,
|
updateDefaultUserRole,
|
||||||
updateJWTExpiresDuration
|
updateJWTExpiresDuration
|
||||||
} from '$lib/apis/auths';
|
} from '$lib/apis/auths';
|
||||||
|
import Switch from '$lib/components/common/Switch.svelte';
|
||||||
import { onMount, getContext } from 'svelte';
|
import { onMount, getContext } from 'svelte';
|
||||||
|
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
export let saveHandler: Function;
|
export let saveHandler: Function;
|
||||||
let signUpEnabled = true;
|
|
||||||
let defaultUserRole = 'pending';
|
|
||||||
let JWTExpiresIn = '';
|
|
||||||
|
|
||||||
|
let adminConfig = null;
|
||||||
let webhookUrl = '';
|
let webhookUrl = '';
|
||||||
let communitySharingEnabled = true;
|
|
||||||
|
|
||||||
const toggleSignUpEnabled = async () => {
|
const updateHandler = async () => {
|
||||||
signUpEnabled = await toggleSignUpEnabledStatus(localStorage.token);
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateDefaultUserRoleHandler = async (role) => {
|
|
||||||
defaultUserRole = await updateDefaultUserRole(localStorage.token, role);
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateJWTExpiresDurationHandler = async (duration) => {
|
|
||||||
JWTExpiresIn = await updateJWTExpiresDuration(localStorage.token, duration);
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateWebhookUrlHandler = async () => {
|
|
||||||
webhookUrl = await updateWebhookUrl(localStorage.token, webhookUrl);
|
webhookUrl = await updateWebhookUrl(localStorage.token, webhookUrl);
|
||||||
};
|
const res = await updateAdminConfig(localStorage.token, adminConfig);
|
||||||
|
|
||||||
const toggleCommunitySharingEnabled = async () => {
|
if (res) {
|
||||||
communitySharingEnabled = await toggleCommunitySharingEnabledStatus(localStorage.token);
|
toast.success(i18n.t('Settings updated successfully'));
|
||||||
|
} else {
|
||||||
|
toast.error(i18n.t('Failed to update settings'));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
(async () => {
|
(async () => {
|
||||||
signUpEnabled = await getSignUpEnabledStatus(localStorage.token);
|
adminConfig = await getAdminConfig(localStorage.token);
|
||||||
})(),
|
|
||||||
(async () => {
|
|
||||||
defaultUserRole = await getDefaultUserRole(localStorage.token);
|
|
||||||
})(),
|
|
||||||
(async () => {
|
|
||||||
JWTExpiresIn = await getJWTExpiresDuration(localStorage.token);
|
|
||||||
})(),
|
})(),
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
webhookUrl = await getWebhookUrl(localStorage.token);
|
webhookUrl = await getWebhookUrl(localStorage.token);
|
||||||
})(),
|
|
||||||
(async () => {
|
|
||||||
communitySharingEnabled = await getCommunitySharingEnabledStatus(localStorage.token);
|
|
||||||
})()
|
})()
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
@ -69,156 +52,94 @@
|
|||||||
<form
|
<form
|
||||||
class="flex flex-col h-full justify-between space-y-3 text-sm"
|
class="flex flex-col h-full justify-between space-y-3 text-sm"
|
||||||
on:submit|preventDefault={() => {
|
on:submit|preventDefault={() => {
|
||||||
updateJWTExpiresDurationHandler(JWTExpiresIn);
|
updateHandler();
|
||||||
updateWebhookUrlHandler();
|
|
||||||
saveHandler();
|
saveHandler();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80">
|
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-[22rem]">
|
||||||
<div>
|
{#if adminConfig !== null}
|
||||||
<div class=" mb-2 text-sm font-medium">{$i18n.t('General Settings')}</div>
|
<div>
|
||||||
|
<div class=" mb-3 text-sm font-medium">{$i18n.t('General Settings')}</div>
|
||||||
|
|
||||||
<div class=" flex w-full justify-between">
|
<div class=" flex w-full justify-between pr-2">
|
||||||
<div class=" self-center text-xs font-medium">{$i18n.t('Enable New Sign Ups')}</div>
|
<div class=" self-center text-xs font-medium">{$i18n.t('Enable New Sign Ups')}</div>
|
||||||
|
|
||||||
<button
|
<Switch bind:state={adminConfig.ENABLE_SIGNUP} />
|
||||||
class="p-1 px-3 text-xs flex rounded transition"
|
</div>
|
||||||
on:click={() => {
|
|
||||||
toggleSignUpEnabled();
|
<div class=" my-3 flex w-full justify-between">
|
||||||
}}
|
<div class=" self-center text-xs font-medium">{$i18n.t('Default User Role')}</div>
|
||||||
type="button"
|
<div class="flex items-center relative">
|
||||||
>
|
<select
|
||||||
{#if signUpEnabled}
|
class="dark:bg-gray-900 w-fit pr-8 rounded px-2 text-xs bg-transparent outline-none text-right"
|
||||||
<svg
|
bind:value={adminConfig.DEFAULT_USER_ROLE}
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
placeholder="Select a role"
|
||||||
viewBox="0 0 16 16"
|
|
||||||
fill="currentColor"
|
|
||||||
class="w-4 h-4"
|
|
||||||
>
|
>
|
||||||
<path
|
<option value="pending">{$i18n.t('pending')}</option>
|
||||||
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"
|
<option value="user">{$i18n.t('user')}</option>
|
||||||
/>
|
<option value="admin">{$i18n.t('admin')}</option>
|
||||||
</svg>
|
</select>
|
||||||
<span class="ml-2 self-center">{$i18n.t('Enabled')}</span>
|
</div>
|
||||||
{:else}
|
</div>
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
<hr class=" dark:border-gray-850 my-2" />
|
||||||
viewBox="0 0 16 16"
|
|
||||||
fill="currentColor"
|
<div class="my-3 flex w-full items-center justify-between pr-2">
|
||||||
class="w-4 h-4"
|
<div class=" self-center text-xs font-medium">
|
||||||
|
{$i18n.t('Show Admin Details in Account Pending Overlay')}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Switch bind:state={adminConfig.SHOW_ADMIN_DETAILS} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="my-3 flex w-full items-center justify-between pr-2">
|
||||||
|
<div class=" self-center text-xs font-medium">{$i18n.t('Enable Community Sharing')}</div>
|
||||||
|
|
||||||
|
<Switch bind:state={adminConfig.ENABLE_COMMUNITY_SHARING} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr class=" dark:border-gray-850 my-2" />
|
||||||
|
|
||||||
|
<div class=" w-full justify-between">
|
||||||
|
<div class="flex w-full justify-between">
|
||||||
|
<div class=" self-center text-xs font-medium">{$i18n.t('JWT Expiration')}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex mt-2 space-x-2">
|
||||||
|
<input
|
||||||
|
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
|
||||||
|
type="text"
|
||||||
|
placeholder={`e.g.) "30m","1h", "10d". `}
|
||||||
|
bind:value={adminConfig.JWT_EXPIRES_IN}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-2 text-xs text-gray-400 dark:text-gray-500">
|
||||||
|
{$i18n.t('Valid time units:')}
|
||||||
|
<span class=" text-gray-300 font-medium"
|
||||||
|
>{$i18n.t("'s', 'm', 'h', 'd', 'w' or '-1' for no expiration.")}</span
|
||||||
>
|
>
|
||||||
<path
|
</div>
|
||||||
fill-rule="evenodd"
|
</div>
|
||||||
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>
|
|
||||||
|
|
||||||
<span class="ml-2 self-center">{$i18n.t('Disabled')}</span>
|
<hr class=" dark:border-gray-850 my-2" />
|
||||||
{/if}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class=" flex w-full justify-between">
|
<div class=" w-full justify-between">
|
||||||
<div class=" self-center text-xs font-medium">{$i18n.t('Default User Role')}</div>
|
<div class="flex w-full justify-between">
|
||||||
<div class="flex items-center relative">
|
<div class=" self-center text-xs font-medium">{$i18n.t('Webhook URL')}</div>
|
||||||
<select
|
</div>
|
||||||
class="dark:bg-gray-900 w-fit pr-8 rounded py-2 px-2 text-xs bg-transparent outline-none text-right"
|
|
||||||
bind:value={defaultUserRole}
|
<div class="flex mt-2 space-x-2">
|
||||||
placeholder="Select a theme"
|
<input
|
||||||
on:change={(e) => {
|
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
|
||||||
updateDefaultUserRoleHandler(e.target.value);
|
type="text"
|
||||||
}}
|
placeholder={`https://example.com/webhook`}
|
||||||
>
|
bind:value={webhookUrl}
|
||||||
<option value="pending">{$i18n.t('pending')}</option>
|
/>
|
||||||
<option value="user">{$i18n.t('user')}</option>
|
</div>
|
||||||
<option value="admin">{$i18n.t('admin')}</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
<div class=" flex w-full justify-between">
|
|
||||||
<div class=" self-center text-xs font-medium">{$i18n.t('Enable Community Sharing')}</div>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="p-1 px-3 text-xs flex rounded transition"
|
|
||||||
on:click={() => {
|
|
||||||
toggleCommunitySharingEnabled();
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
{#if communitySharingEnabled}
|
|
||||||
<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>
|
|
||||||
<span class="ml-2 self-center">{$i18n.t('Enabled')}</span>
|
|
||||||
{: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>
|
|
||||||
|
|
||||||
<span class="ml-2 self-center">{$i18n.t('Disabled')}</span>
|
|
||||||
{/if}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<hr class=" dark:border-gray-700 my-3" />
|
|
||||||
|
|
||||||
<div class=" w-full justify-between">
|
|
||||||
<div class="flex w-full justify-between">
|
|
||||||
<div class=" self-center text-xs font-medium">{$i18n.t('Webhook URL')}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex mt-2 space-x-2">
|
|
||||||
<input
|
|
||||||
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
|
|
||||||
type="text"
|
|
||||||
placeholder={`https://example.com/webhook`}
|
|
||||||
bind:value={webhookUrl}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<hr class=" dark:border-gray-700 my-3" />
|
|
||||||
|
|
||||||
<div class=" w-full justify-between">
|
|
||||||
<div class="flex w-full justify-between">
|
|
||||||
<div class=" self-center text-xs font-medium">{$i18n.t('JWT Expiration')}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex mt-2 space-x-2">
|
|
||||||
<input
|
|
||||||
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
|
|
||||||
type="text"
|
|
||||||
placeholder={`e.g.) "30m","1h", "10d". `}
|
|
||||||
bind:value={JWTExpiresIn}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mt-2 text-xs text-gray-400 dark:text-gray-500">
|
|
||||||
{$i18n.t('Valid time units:')}
|
|
||||||
<span class=" text-gray-300 font-medium"
|
|
||||||
>{$i18n.t("'s', 'm', 'h', 'd', 'w' or '-1' for no expiration.")}</span
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-end pt-3 text-sm font-medium">
|
<div class="flex justify-end pt-3 text-sm font-medium">
|
||||||
|
59
src/lib/components/layout/Overlay/AccountPending.svelte
Normal file
59
src/lib/components/layout/Overlay/AccountPending.svelte
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { getAdminDetails } from '$lib/apis/auths';
|
||||||
|
import { onMount, tick, getContext } from 'svelte';
|
||||||
|
|
||||||
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
|
let adminDetails = null;
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
adminDetails = await getAdminDetails(localStorage.token).catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="fixed w-full h-full flex z-[999]">
|
||||||
|
<div
|
||||||
|
class="absolute w-full h-full backdrop-blur-lg bg-white/10 dark:bg-gray-900/50 flex justify-center"
|
||||||
|
>
|
||||||
|
<div class="m-auto pb-10 flex flex-col justify-center">
|
||||||
|
<div class="max-w-md">
|
||||||
|
<div class="text-center dark:text-white text-2xl font-medium z-50">
|
||||||
|
Account Activation Pending<br /> Contact Admin for WebUI Access
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class=" mt-4 text-center text-sm dark:text-gray-200 w-full">
|
||||||
|
Your account status is currently pending activation.<br /> To access the WebUI, please reach
|
||||||
|
out to the administrator. Admins can manage user statuses from the Admin Panel.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if adminDetails}
|
||||||
|
<div class="mt-4 text-sm font-medium text-center">
|
||||||
|
<div>Admin: {adminDetails.name} ({adminDetails.email})</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div class=" mt-6 mx-auto relative group w-fit">
|
||||||
|
<button
|
||||||
|
class="relative z-20 flex px-5 py-2 rounded-full bg-white border border-gray-100 dark:border-none hover:bg-gray-100 text-gray-700 transition font-medium text-sm"
|
||||||
|
on:click={async () => {
|
||||||
|
location.href = '/';
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{$i18n.t('Check Again')}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="text-xs text-center w-full mt-2 text-gray-400 underline"
|
||||||
|
on:click={async () => {
|
||||||
|
localStorage.removeItem('token');
|
||||||
|
location.href = '/auth';
|
||||||
|
}}>{$i18n.t('Sign Out')}</button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -37,6 +37,8 @@
|
|||||||
import { getBanners } from '$lib/apis/configs';
|
import { getBanners } from '$lib/apis/configs';
|
||||||
import { getUserSettings } from '$lib/apis/users';
|
import { getUserSettings } from '$lib/apis/users';
|
||||||
import Help from '$lib/components/layout/Help.svelte';
|
import Help from '$lib/components/layout/Help.svelte';
|
||||||
|
import AccountPending from '$lib/components/layout/Overlay/AccountPending.svelte';
|
||||||
|
import { error } from '@sveltejs/kit';
|
||||||
|
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
@ -74,7 +76,10 @@
|
|||||||
// IndexedDB Not Found
|
// IndexedDB Not Found
|
||||||
}
|
}
|
||||||
|
|
||||||
const userSettings = await getUserSettings(localStorage.token);
|
const userSettings = await getUserSettings(localStorage.token).catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
if (userSettings) {
|
if (userSettings) {
|
||||||
await settings.set(userSettings.ui);
|
await settings.set(userSettings.ui);
|
||||||
@ -186,44 +191,7 @@
|
|||||||
>
|
>
|
||||||
{#if loaded}
|
{#if loaded}
|
||||||
{#if !['user', 'admin'].includes($user.role)}
|
{#if !['user', 'admin'].includes($user.role)}
|
||||||
<div class="fixed w-full h-full flex z-[999]">
|
<AccountPending />
|
||||||
<div
|
|
||||||
class="absolute w-full h-full backdrop-blur-lg bg-white/10 dark:bg-gray-900/50 flex justify-center"
|
|
||||||
>
|
|
||||||
<div class="m-auto pb-10 flex flex-col justify-center">
|
|
||||||
<div class="max-w-md">
|
|
||||||
<div class="text-center dark:text-white text-2xl font-medium z-50">
|
|
||||||
Account Activation Pending<br /> Contact Admin for WebUI Access
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class=" mt-4 text-center text-sm dark:text-gray-200 w-full">
|
|
||||||
Your account status is currently pending activation. To access the WebUI, please
|
|
||||||
reach out to the administrator. Admins can manage user statuses from the Admin
|
|
||||||
Panel.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class=" mt-6 mx-auto relative group w-fit">
|
|
||||||
<button
|
|
||||||
class="relative z-20 flex px-5 py-2 rounded-full bg-white border border-gray-100 dark:border-none hover:bg-gray-100 text-gray-700 transition font-medium text-sm"
|
|
||||||
on:click={async () => {
|
|
||||||
location.href = '/';
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{$i18n.t('Check Again')}
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="text-xs text-center w-full mt-2 text-gray-400 underline"
|
|
||||||
on:click={async () => {
|
|
||||||
localStorage.removeItem('token');
|
|
||||||
location.href = '/auth';
|
|
||||||
}}>{$i18n.t('Sign Out')}</button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{:else if localDBChats.length > 0}
|
{:else if localDBChats.length > 0}
|
||||||
<div class="fixed w-full h-full flex z-50">
|
<div class="fixed w-full h-full flex z-50">
|
||||||
<div
|
<div
|
||||||
|
Loading…
Reference in New Issue
Block a user