mirror of
https://github.com/coaidev/coai.git
synced 2025-05-19 21:10:18 +09:00
parent
4f4bc1561b
commit
40cb56761d
@ -33,6 +33,7 @@ export type SearchState = {
|
|||||||
|
|
||||||
export type SiteState = {
|
export type SiteState = {
|
||||||
close_register: boolean;
|
close_register: boolean;
|
||||||
|
close_relay: boolean;
|
||||||
relay_plan: boolean;
|
relay_plan: boolean;
|
||||||
quota: number;
|
quota: number;
|
||||||
buy_link: string;
|
buy_link: string;
|
||||||
@ -123,8 +124,9 @@ export const initialSystemState: SystemProps = {
|
|||||||
pwa_manifest: "",
|
pwa_manifest: "",
|
||||||
},
|
},
|
||||||
site: {
|
site: {
|
||||||
relay_plan: false,
|
|
||||||
close_register: false,
|
close_register: false,
|
||||||
|
close_relay: false,
|
||||||
|
relay_plan: false,
|
||||||
quota: 0,
|
quota: 0,
|
||||||
buy_link: "",
|
buy_link: "",
|
||||||
announcement: "",
|
announcement: "",
|
||||||
|
@ -706,6 +706,8 @@
|
|||||||
"searchPlaceholder": "DuckDuckGo 接入点 (格式仅需填写 https://example.com)",
|
"searchPlaceholder": "DuckDuckGo 接入点 (格式仅需填写 https://example.com)",
|
||||||
"closeRegistration": "暂停注册",
|
"closeRegistration": "暂停注册",
|
||||||
"closeRegistrationTip": "暂停注册,关闭后新用户将无法注册",
|
"closeRegistrationTip": "暂停注册,关闭后新用户将无法注册",
|
||||||
|
"closeRelay": "关闭中转 API",
|
||||||
|
"closeRelayTip": "关闭中转 API,关闭后中转 API 将无法使用",
|
||||||
"relayPlan": "订阅配额支持中转 API",
|
"relayPlan": "订阅配额支持中转 API",
|
||||||
"relayPlanTip": "订阅配额支持中转 API,开启后中转 API 计费会优先考虑使用用户订阅配额\n(提示:订阅为次数配额,对 Token 计费的模型可能会影响成本)",
|
"relayPlanTip": "订阅配额支持中转 API,开启后中转 API 计费会优先考虑使用用户订阅配额\n(提示:订阅为次数配额,对 Token 计费的模型可能会影响成本)",
|
||||||
"quota": "用户初始点数",
|
"quota": "用户初始点数",
|
||||||
|
@ -564,7 +564,9 @@
|
|||||||
"searchPlaceholder": "DuckDuckGo Access Point (Format only https://example.com)",
|
"searchPlaceholder": "DuckDuckGo Access Point (Format only https://example.com)",
|
||||||
"image_store": "Picture storage",
|
"image_store": "Picture storage",
|
||||||
"image_storeTip": "Images generated by the OpenAI channel DALL-E will be stored on the server to prevent invalidation of the images",
|
"image_storeTip": "Images generated by the OpenAI channel DALL-E will be stored on the server to prevent invalidation of the images",
|
||||||
"image_storeNoBackend": "No backend domain configured, cannot enable image storage"
|
"image_storeNoBackend": "No backend domain configured, cannot enable image storage",
|
||||||
|
"closeRelay": "Turn off Staging API",
|
||||||
|
"closeRelayTip": "Turn off the staging API, the staging API will not be available after turning off"
|
||||||
},
|
},
|
||||||
"user": "Users",
|
"user": "Users",
|
||||||
"invitation-code": "Invitation Code",
|
"invitation-code": "Invitation Code",
|
||||||
|
@ -564,7 +564,9 @@
|
|||||||
"searchPlaceholder": "DuckDuckGoアクセスポイント(フォーマットのみhttps://example.com )",
|
"searchPlaceholder": "DuckDuckGoアクセスポイント(フォーマットのみhttps://example.com )",
|
||||||
"image_store": "画像ストレージ",
|
"image_store": "画像ストレージ",
|
||||||
"image_storeTip": "OpenAIチャンネルDALL - Eによって生成された画像は、画像の無効化を防ぐためにサーバーに保存されます",
|
"image_storeTip": "OpenAIチャンネルDALL - Eによって生成された画像は、画像の無効化を防ぐためにサーバーに保存されます",
|
||||||
"image_storeNoBackend": "バックエンドドメインが設定されていません。画像ストレージを有効にできません"
|
"image_storeNoBackend": "バックエンドドメインが設定されていません。画像ストレージを有効にできません",
|
||||||
|
"closeRelay": "ステージングAPIをオフにする",
|
||||||
|
"closeRelayTip": "ステージングAPIをオフにすると、オフにするとステージングAPIは使用できなくなります"
|
||||||
},
|
},
|
||||||
"user": "ユーザー管理",
|
"user": "ユーザー管理",
|
||||||
"invitation-code": "招待コード",
|
"invitation-code": "招待コード",
|
||||||
|
@ -564,7 +564,9 @@
|
|||||||
"searchPlaceholder": "Точка доступа DuckDuckGo (только в формате https://example.com)",
|
"searchPlaceholder": "Точка доступа DuckDuckGo (только в формате https://example.com)",
|
||||||
"image_store": "Хранение изображений",
|
"image_store": "Хранение изображений",
|
||||||
"image_storeTip": "Изображения, сгенерированные каналом OpenAI DALL-E, будут храниться на сервере, чтобы предотвратить недействительность изображений",
|
"image_storeTip": "Изображения, сгенерированные каналом OpenAI DALL-E, будут храниться на сервере, чтобы предотвратить недействительность изображений",
|
||||||
"image_storeNoBackend": "Нет настроенного внутреннего домена, невозможно включить хранение изображений"
|
"image_storeNoBackend": "Нет настроенного внутреннего домена, невозможно включить хранение изображений",
|
||||||
|
"closeRelay": "Отключить Staging API",
|
||||||
|
"closeRelayTip": "Отключите промежуточный API, промежуточный API будет недоступен после отключения"
|
||||||
},
|
},
|
||||||
"user": "Управление пользователями",
|
"user": "Управление пользователями",
|
||||||
"invitation-code": "Код приглашения",
|
"invitation-code": "Код приглашения",
|
||||||
|
@ -44,7 +44,7 @@ import {
|
|||||||
} from "@/components/ui/dialog.tsx";
|
} from "@/components/ui/dialog.tsx";
|
||||||
import { DialogTitle } from "@radix-ui/react-dialog";
|
import { DialogTitle } from "@radix-ui/react-dialog";
|
||||||
import Require from "@/components/Require.tsx";
|
import Require from "@/components/Require.tsx";
|
||||||
import { Loader2, PencilLine, Settings2 } from "lucide-react";
|
import { PencilLine, RotateCw, Save, Settings2 } from "lucide-react";
|
||||||
import { FlexibleTextarea } from "@/components/ui/textarea.tsx";
|
import { FlexibleTextarea } from "@/components/ui/textarea.tsx";
|
||||||
import Tips from "@/components/Tips.tsx";
|
import Tips from "@/components/Tips.tsx";
|
||||||
import { cn } from "@/components/ui/lib/utils.ts";
|
import { cn } from "@/components/ui/lib/utils.ts";
|
||||||
@ -497,6 +497,21 @@ function Site({ data, dispatch, onChange }: CompProps<SiteState>) {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</ParagraphItem>
|
</ParagraphItem>
|
||||||
|
<ParagraphItem>
|
||||||
|
<Label>
|
||||||
|
{t("admin.system.closeRelay")}
|
||||||
|
<Tips
|
||||||
|
className={`inline-block`}
|
||||||
|
content={t("admin.system.closeRelayTip")}
|
||||||
|
/>
|
||||||
|
</Label>
|
||||||
|
<Switch
|
||||||
|
checked={data.close_relay}
|
||||||
|
onCheckedChange={(value) => {
|
||||||
|
dispatch({ type: "update:site.close_relay", value });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</ParagraphItem>
|
||||||
<ParagraphItem>
|
<ParagraphItem>
|
||||||
<Label>
|
<Label>
|
||||||
{t("admin.system.relayPlan")}
|
{t("admin.system.relayPlan")}
|
||||||
@ -843,7 +858,7 @@ function System() {
|
|||||||
if (doToast !== false) toastState(toast, t, res, true);
|
if (doToast !== false) toastState(toast, t, res, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffectAsync(async () => {
|
const doRefresh = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const res = await getConfig();
|
const res = await getConfig();
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@ -851,18 +866,36 @@ function System() {
|
|||||||
if (res.status) {
|
if (res.status) {
|
||||||
setData({ type: "set", value: res.data });
|
setData({ type: "set", value: res.data });
|
||||||
}
|
}
|
||||||
}, []);
|
};
|
||||||
|
|
||||||
|
useEffectAsync(doRefresh, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`system`}>
|
<div className={`system`}>
|
||||||
<Card className={`admin-card system-card`}>
|
<Card className={`admin-card system-card`}>
|
||||||
<CardHeader className={`select-none`}>
|
<CardHeader className={`select-none`}>
|
||||||
<CardTitle>
|
<CardTitle>{t("admin.settings")}</CardTitle>
|
||||||
{t("admin.settings")}
|
|
||||||
{loading && <Loader2 className={`h-4 w-4 ml-2 inline-block`} />}
|
|
||||||
</CardTitle>
|
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className={`flex flex-col gap-1`}>
|
<CardContent className={`flex flex-col gap-1`}>
|
||||||
|
<div className={`system-actions flex flex-row`}>
|
||||||
|
<div className={`grow`} />
|
||||||
|
<Button
|
||||||
|
size={`icon`}
|
||||||
|
variant={`outline`}
|
||||||
|
loading={true}
|
||||||
|
className={`mr-2`}
|
||||||
|
onClick={async () => await doRefresh()}
|
||||||
|
>
|
||||||
|
<RotateCw className={cn(loading && `animate-spin`, `h-4 w-4`)} />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size={`icon`}
|
||||||
|
loading={true}
|
||||||
|
onClick={async () => await doSaving()}
|
||||||
|
>
|
||||||
|
<Save className={`h-4 w-4`} />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
<General
|
<General
|
||||||
form={data}
|
form={data}
|
||||||
data={data.general}
|
data={data.general}
|
||||||
|
@ -196,7 +196,7 @@ func DeepLogin(c *gin.Context, token string) (string, error) {
|
|||||||
|
|
||||||
db := utils.GetDBFromContext(c)
|
db := utils.GetDBFromContext(c)
|
||||||
if !IsUserExist(db, user.Username) {
|
if !IsUserExist(db, user.Username) {
|
||||||
if channel.SystemInstance.IsCloseRegister() {
|
if globals.CloseRegistration {
|
||||||
return "", errors.New("this site is not open for registration")
|
return "", errors.New("this site is not open for registration")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package auth
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"chat/channel"
|
"chat/channel"
|
||||||
|
"chat/globals"
|
||||||
"chat/utils"
|
"chat/utils"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -143,7 +144,7 @@ func RegisterAPI(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if channel.SystemInstance.IsCloseRegister() {
|
if globals.CloseRegistration {
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"status": false,
|
"status": false,
|
||||||
"error": "this site is not open for registration",
|
"error": "this site is not open for registration",
|
||||||
|
@ -35,6 +35,7 @@ type generalState struct {
|
|||||||
|
|
||||||
type siteState struct {
|
type siteState struct {
|
||||||
CloseRegister bool `json:"close_register" mapstructure:"closeregister"`
|
CloseRegister bool `json:"close_register" mapstructure:"closeregister"`
|
||||||
|
CloseRelay bool `json:"close_relay" mapstructure:"closerelay"`
|
||||||
RelayPlan bool `json:"relay_plan" mapstructure:"relayplan"`
|
RelayPlan bool `json:"relay_plan" mapstructure:"relayplan"`
|
||||||
Quota float64 `json:"quota" mapstructure:"quota"`
|
Quota float64 `json:"quota" mapstructure:"quota"`
|
||||||
BuyLink string `json:"buy_link" mapstructure:"buylink"`
|
BuyLink string `json:"buy_link" mapstructure:"buylink"`
|
||||||
@ -94,6 +95,9 @@ func NewSystemConfig() *SystemConfig {
|
|||||||
func (c *SystemConfig) Load() {
|
func (c *SystemConfig) Load() {
|
||||||
globals.NotifyUrl = c.GetBackend()
|
globals.NotifyUrl = c.GetBackend()
|
||||||
|
|
||||||
|
globals.CloseRegistration = c.Site.CloseRegister
|
||||||
|
globals.CloseRelay = c.Site.CloseRelay
|
||||||
|
|
||||||
globals.ArticlePermissionGroup = c.Common.Article
|
globals.ArticlePermissionGroup = c.Common.Article
|
||||||
globals.GenerationPermissionGroup = c.Common.Generation
|
globals.GenerationPermissionGroup = c.Common.Generation
|
||||||
globals.CacheAcceptedModels = c.Common.Cache
|
globals.CacheAcceptedModels = c.Common.Cache
|
||||||
@ -282,10 +286,6 @@ func (c *SystemConfig) AcceptImageStore() bool {
|
|||||||
return c.Common.ImageStore
|
return c.Common.ImageStore
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *SystemConfig) IsCloseRegister() bool {
|
|
||||||
return c.Site.CloseRegister
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *SystemConfig) SupportRelayPlan() bool {
|
func (c *SystemConfig) SupportRelayPlan() bool {
|
||||||
return c.Site.RelayPlan
|
return c.Site.RelayPlan
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,8 @@ var CacheAcceptedModels []string
|
|||||||
var CacheAcceptedExpire int64
|
var CacheAcceptedExpire int64
|
||||||
var CacheAcceptedSize int64
|
var CacheAcceptedSize int64
|
||||||
var AcceptImageStore bool
|
var AcceptImageStore bool
|
||||||
|
var CloseRegistration bool
|
||||||
|
var CloseRelay bool
|
||||||
|
|
||||||
func OriginIsAllowed(uri string) bool {
|
func OriginIsAllowed(uri string) bool {
|
||||||
if len(AllowedOrigins) == 0 {
|
if len(AllowedOrigins) == 0 {
|
||||||
|
@ -26,6 +26,11 @@ func supportRelayPlan() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ChatRelayAPI(c *gin.Context) {
|
func ChatRelayAPI(c *gin.Context) {
|
||||||
|
if globals.CloseRelay {
|
||||||
|
abortWithErrorResponse(c, fmt.Errorf("relay api is denied of access"), "access_denied_error")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
username := utils.GetUserFromContext(c)
|
username := utils.GetUserFromContext(c)
|
||||||
if username == "" {
|
if username == "" {
|
||||||
abortWithErrorResponse(c, fmt.Errorf("access denied for invalid api key"), "authentication_error")
|
abortWithErrorResponse(c, fmt.Errorf("access denied for invalid api key"), "authentication_error")
|
||||||
|
@ -15,6 +15,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func ImagesRelayAPI(c *gin.Context) {
|
func ImagesRelayAPI(c *gin.Context) {
|
||||||
|
if globals.CloseRelay {
|
||||||
|
abortWithErrorResponse(c, fmt.Errorf("relay api is denied of access"), "access_denied_error")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
username := utils.GetUserFromContext(c)
|
username := utils.GetUserFromContext(c)
|
||||||
if username == "" {
|
if username == "" {
|
||||||
abortWithErrorResponse(c, fmt.Errorf("access denied for invalid api key"), "authentication_error")
|
abortWithErrorResponse(c, fmt.Errorf("access denied for invalid api key"), "authentication_error")
|
||||||
|
Loading…
Reference in New Issue
Block a user