mirror of
https://github.com/wgh136/nysoure.git
synced 2025-09-27 20:27:23 +00:00
Allow normal user to upload.
This commit is contained in:
@@ -36,6 +36,8 @@
|
|||||||
window.serverName = "{{SiteName}}";
|
window.serverName = "{{SiteName}}";
|
||||||
window.cloudflareTurnstileSiteKey = "{{CFTurnstileSiteKey}}";
|
window.cloudflareTurnstileSiteKey = "{{CFTurnstileSiteKey}}";
|
||||||
window.siteInfo = `{{SiteInfo}}`;
|
window.siteInfo = `{{SiteInfo}}`;
|
||||||
|
window.uploadPrompt = `{{UploadPrompt}}`;
|
||||||
|
window.allowNormalUserUpload = `{{AllowNormalUserUpload}}`;
|
||||||
</script>
|
</script>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
<script type="module" src="/src/main.tsx"></script>
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
|
@@ -4,6 +4,8 @@ interface MyWindow extends Window {
|
|||||||
serverName?: string;
|
serverName?: string;
|
||||||
cloudflareTurnstileSiteKey?: string;
|
cloudflareTurnstileSiteKey?: string;
|
||||||
siteInfo?: string;
|
siteInfo?: string;
|
||||||
|
uploadPrompt?: string;
|
||||||
|
allowNormalUserUpload?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
class App {
|
class App {
|
||||||
@@ -17,6 +19,10 @@ class App {
|
|||||||
|
|
||||||
siteInfo = "";
|
siteInfo = "";
|
||||||
|
|
||||||
|
uploadPrompt = "";
|
||||||
|
|
||||||
|
allowNormalUserUpload = true;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
@@ -37,6 +43,8 @@ class App {
|
|||||||
this.cloudflareTurnstileSiteKey = null; // Placeholder value, set to null if not configured
|
this.cloudflareTurnstileSiteKey = null; // Placeholder value, set to null if not configured
|
||||||
}
|
}
|
||||||
this.siteInfo = (window as MyWindow).siteInfo || "";
|
this.siteInfo = (window as MyWindow).siteInfo || "";
|
||||||
|
this.uploadPrompt = (window as MyWindow).uploadPrompt || "";
|
||||||
|
// this.allowNormalUserUpload = (window as MyWindow).allowNormalUserUpload === "true";
|
||||||
}
|
}
|
||||||
|
|
||||||
saveData() {
|
saveData() {
|
||||||
|
@@ -93,6 +93,7 @@ export interface Storage {
|
|||||||
maxSize: number;
|
maxSize: number;
|
||||||
currentSize: number;
|
currentSize: number;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
|
isDefault: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RFile {
|
export interface RFile {
|
||||||
@@ -157,6 +158,9 @@ export interface ServerConfig {
|
|||||||
server_name: string;
|
server_name: string;
|
||||||
server_description: string;
|
server_description: string;
|
||||||
site_info: string;
|
site_info: string;
|
||||||
|
allow_normal_user_upload: boolean;
|
||||||
|
max_normal_user_upload_size_in_mb: number;
|
||||||
|
upload_prompt: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum RSort {
|
export enum RSort {
|
||||||
|
@@ -460,6 +460,12 @@ class Network {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async setDefaultStorage(id: number): Promise<Response<Storage>> {
|
||||||
|
return this._callApi(() =>
|
||||||
|
axios.put(`${this.apiBaseUrl}/storage/${id}/default`),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async initFileUpload(
|
async initFileUpload(
|
||||||
filename: string,
|
filename: string,
|
||||||
description: string,
|
description: string,
|
||||||
|
@@ -108,7 +108,7 @@ export default function ManageServerConfigPage() {
|
|||||||
}}
|
}}
|
||||||
></Input>
|
></Input>
|
||||||
<fieldset className="fieldset w-full">
|
<fieldset className="fieldset w-full">
|
||||||
<legend className="fieldset-legend">Allow register</legend>
|
<legend className="fieldset-legend">Allow registration</legend>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={config.allow_register}
|
checked={config.allow_register}
|
||||||
@@ -164,6 +164,36 @@ export default function ManageServerConfigPage() {
|
|||||||
label="Site info (Markdown)"
|
label="Site info (Markdown)"
|
||||||
height={180}
|
height={180}
|
||||||
/>
|
/>
|
||||||
|
<fieldset className="fieldset w-full">
|
||||||
|
<legend className="fieldset-legend">Allow normal user upload</legend>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={config.allow_normal_user_upload}
|
||||||
|
className="toggle-primary toggle"
|
||||||
|
onChange={(e) => {
|
||||||
|
setConfig({ ...config, allow_normal_user_upload: e.target.checked });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</fieldset>
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
value={config.max_normal_user_upload_size_in_mb.toString()}
|
||||||
|
label="Max normal user upload size (MB)"
|
||||||
|
onChange={(e) => {
|
||||||
|
setConfig({
|
||||||
|
...config,
|
||||||
|
max_normal_user_upload_size_in_mb: parseInt(e.target.value),
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
></Input>
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
value={config.upload_prompt}
|
||||||
|
label="Upload prompt"
|
||||||
|
onChange={(e) => {
|
||||||
|
setConfig({ ...config, upload_prompt: e.target.value });
|
||||||
|
}}
|
||||||
|
></Input>
|
||||||
<InfoAlert
|
<InfoAlert
|
||||||
className="my-2"
|
className="my-2"
|
||||||
message="If the cloudflare turnstile keys are not empty, the turnstile will be used for register and download."
|
message="If the cloudflare turnstile keys are not empty, the turnstile will be used for register and download."
|
||||||
|
@@ -3,10 +3,12 @@ import { Storage } from "../network/models.ts";
|
|||||||
import { network } from "../network/network.ts";
|
import { network } from "../network/network.ts";
|
||||||
import showToast from "../components/toast.ts";
|
import showToast from "../components/toast.ts";
|
||||||
import Loading from "../components/loading.tsx";
|
import Loading from "../components/loading.tsx";
|
||||||
import { MdAdd, MdDelete } from "react-icons/md";
|
import { MdAdd, MdMoreHoriz } from "react-icons/md";
|
||||||
import { ErrorAlert } from "../components/alert.tsx";
|
import { ErrorAlert } from "../components/alert.tsx";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { app } from "../app.ts";
|
import { app } from "../app.ts";
|
||||||
|
import showPopup, { PopupMenuItem } from "../components/popup.tsx";
|
||||||
|
import Badge from "../components/badge.tsx";
|
||||||
|
|
||||||
export default function StorageView() {
|
export default function StorageView() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -84,6 +86,26 @@ export default function StorageView() {
|
|||||||
setLoadingId(null);
|
setLoadingId(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSetDefault = async (id: number) => {
|
||||||
|
if (loadingId != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setLoadingId(id);
|
||||||
|
const response = await network.setDefaultStorage(id);
|
||||||
|
if (response.success) {
|
||||||
|
showToast({
|
||||||
|
message: t("Storage set as default successfully"),
|
||||||
|
});
|
||||||
|
updateStorages();
|
||||||
|
} else {
|
||||||
|
showToast({
|
||||||
|
message: response.message,
|
||||||
|
type: "error",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setLoadingId(null);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
@@ -121,7 +143,10 @@ export default function StorageView() {
|
|||||||
{storages.map((s) => {
|
{storages.map((s) => {
|
||||||
return (
|
return (
|
||||||
<tr key={s.id} className={"hover"}>
|
<tr key={s.id} className={"hover"}>
|
||||||
<td>{s.name}</td>
|
<td>
|
||||||
|
{s.name}
|
||||||
|
{s.isDefault && <Badge className={"ml-1"}>{t("Default")}</Badge>}
|
||||||
|
</td>
|
||||||
<td>{new Date(s.createdAt).toLocaleString()}</td>
|
<td>{new Date(s.createdAt).toLocaleString()}</td>
|
||||||
<td>
|
<td>
|
||||||
{(s.currentSize / 1024 / 1024).toFixed(2)} /{" "}
|
{(s.currentSize / 1024 / 1024).toFixed(2)} /{" "}
|
||||||
@@ -129,21 +154,47 @@ export default function StorageView() {
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<button
|
<button
|
||||||
|
id={`set_default_button_${s.id}`}
|
||||||
className={"btn btn-square"}
|
className={"btn btn-square"}
|
||||||
type={"button"}
|
type={"button"}
|
||||||
|
onClick={() => {
|
||||||
|
showPopup(
|
||||||
|
<ul className="menu bg-base-100 rounded-box z-1 w-64 p-2 shadow-sm">
|
||||||
|
<h4 className="text-sm font-bold px-3 py-1 text-primary">
|
||||||
|
{t("Actions")}
|
||||||
|
</h4>
|
||||||
|
<PopupMenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const dialog = document.getElementById(
|
const dialog = document.getElementById(
|
||||||
`confirm_delete_dialog_${s.id}`,
|
`confirm_delete_dialog_${s.id}`,
|
||||||
) as HTMLDialogElement;
|
) as HTMLDialogElement;
|
||||||
dialog.showModal();
|
dialog.showModal();
|
||||||
}}
|
}}
|
||||||
|
>
|
||||||
|
<a>{t("Delete")}</a>
|
||||||
|
</PopupMenuItem>
|
||||||
|
{!s.isDefault && <PopupMenuItem
|
||||||
|
onClick={() => {
|
||||||
|
handleSetDefault(s.id);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<a>
|
||||||
|
t("Set as Default")
|
||||||
|
</a>
|
||||||
|
</PopupMenuItem>}
|
||||||
|
</ul>,
|
||||||
|
document.getElementById(
|
||||||
|
`set_default_button_${s.id}`,
|
||||||
|
)!,
|
||||||
|
);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{loadingId === s.id ? (
|
{loadingId === s.id ? (
|
||||||
<span
|
<span
|
||||||
className={"loading loading-spinner loading-sm"}
|
className={"loading loading-spinner loading-sm"}
|
||||||
></span>
|
></span>
|
||||||
) : (
|
) : (
|
||||||
<MdDelete size={24} />
|
<MdMoreHoriz size={24} />
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
<dialog
|
<dialog
|
||||||
|
@@ -404,7 +404,6 @@ function Article({ resource }: { resource: ResourceDetails }) {
|
|||||||
<Markdown
|
<Markdown
|
||||||
components={{
|
components={{
|
||||||
p: ({ node, ...props }) => {
|
p: ({ node, ...props }) => {
|
||||||
console.log(props.children);
|
|
||||||
if (
|
if (
|
||||||
typeof props.children === "object" &&
|
typeof props.children === "object" &&
|
||||||
(props.children as ReactElement).type === "strong"
|
(props.children as ReactElement).type === "strong"
|
||||||
@@ -722,7 +721,7 @@ function Files({ files, resourceID }: { files: RFile[]; resourceID: number }) {
|
|||||||
return <FileTile file={file} key={file.id}></FileTile>;
|
return <FileTile file={file} key={file.id}></FileTile>;
|
||||||
})}
|
})}
|
||||||
<div className={"h-2"}></div>
|
<div className={"h-2"}></div>
|
||||||
{app.canUpload() && (
|
{app.canUpload() || app.allowNormalUserUpload && (
|
||||||
<div className={"flex flex-row-reverse"}>
|
<div className={"flex flex-row-reverse"}>
|
||||||
<CreateFileDialog resourceId={resourceID}></CreateFileDialog>
|
<CreateFileDialog resourceId={resourceID}></CreateFileDialog>
|
||||||
</div>
|
</div>
|
||||||
@@ -876,6 +875,12 @@ function CreateFileDialog({ resourceId }: { resourceId: number }) {
|
|||||||
showToast({ message: res.message, type: "error" });
|
showToast({ message: res.message, type: "error" });
|
||||||
} else {
|
} else {
|
||||||
storages.current = res.data!;
|
storages.current = res.data!;
|
||||||
|
let defaultStorage = storages.current.find((s) => s.isDefault);
|
||||||
|
if (!defaultStorage && storages.current.length > 0) {
|
||||||
|
defaultStorage = storages.current[0];
|
||||||
|
}
|
||||||
|
console.log("defaultStorage", defaultStorage);
|
||||||
|
setStorage(defaultStorage || null);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
const dialog = document.getElementById(
|
const dialog = document.getElementById(
|
||||||
"upload_dialog",
|
"upload_dialog",
|
||||||
@@ -902,6 +907,10 @@ function CreateFileDialog({ resourceId }: { resourceId: number }) {
|
|||||||
<div className="modal-box">
|
<div className="modal-box">
|
||||||
<h3 className="font-bold text-lg mb-2">{t("Create File")}</h3>
|
<h3 className="font-bold text-lg mb-2">{t("Create File")}</h3>
|
||||||
|
|
||||||
|
{app.uploadPrompt && (
|
||||||
|
<p className={"text-sm p-2"}>{app.uploadPrompt}</p>
|
||||||
|
)}
|
||||||
|
|
||||||
<p className={"text-sm font-bold p-2"}>{t("Type")}</p>
|
<p className={"text-sm font-bold p-2"}>{t("Type")}</p>
|
||||||
<form className="filter mb-2">
|
<form className="filter mb-2">
|
||||||
<input
|
<input
|
||||||
@@ -980,8 +989,9 @@ function CreateFileDialog({ resourceId }: { resourceId: number }) {
|
|||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
<select
|
<select
|
||||||
|
disabled={!app.canUpload()} // normal user cannot choose storage
|
||||||
className="select select-primary w-full my-2"
|
className="select select-primary w-full my-2"
|
||||||
defaultValue={""}
|
value={storage?.id || ""}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const id = parseInt(e.target.value);
|
const id = parseInt(e.target.value);
|
||||||
if (isNaN(id)) {
|
if (isNaN(id)) {
|
||||||
@@ -1027,7 +1037,15 @@ function CreateFileDialog({ resourceId }: { resourceId: number }) {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{fileType === FileType.serverTask && (
|
{fileType === FileType.serverTask && !app.canUpload() && (
|
||||||
|
<p className={"text-sm p-2"}>
|
||||||
|
{t(
|
||||||
|
"You do not have permission to upload files, please contact the administrator.",
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{fileType === FileType.serverTask && app.canUpload() && (
|
||||||
<>
|
<>
|
||||||
<p className={"text-sm p-2"}>
|
<p className={"text-sm p-2"}>
|
||||||
{t(
|
{t(
|
||||||
@@ -1035,8 +1053,9 @@ function CreateFileDialog({ resourceId }: { resourceId: number }) {
|
|||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
<select
|
<select
|
||||||
|
disabled={!app.canUpload()}
|
||||||
className="select select-primary w-full my-2"
|
className="select select-primary w-full my-2"
|
||||||
defaultValue={""}
|
value={storage?.id || ""}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const id = parseInt(e.target.value);
|
const id = parseInt(e.target.value);
|
||||||
if (isNaN(id)) {
|
if (isNaN(id)) {
|
||||||
|
@@ -109,10 +109,34 @@ func handleDeleteStorage(c fiber.Ctx) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleSetDefaultStorage(c fiber.Ctx) error {
|
||||||
|
idStr := c.Params("id")
|
||||||
|
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return model.NewRequestError("Invalid storage ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
uid, ok := c.Locals("uid").(uint)
|
||||||
|
if !ok {
|
||||||
|
return model.NewUnAuthorizedError("You are not authorized to perform this action")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = service.SetDefaultStorage(uid, uint(id))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusOK).JSON(model.Response[any]{
|
||||||
|
Success: true,
|
||||||
|
Message: "Default storage set successfully",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func AddStorageRoutes(r fiber.Router) {
|
func AddStorageRoutes(r fiber.Router) {
|
||||||
s := r.Group("storage")
|
s := r.Group("storage")
|
||||||
s.Post("/s3", handleCreateS3Storage)
|
s.Post("/s3", handleCreateS3Storage)
|
||||||
s.Post("/local", handleCreateLocalStorage)
|
s.Post("/local", handleCreateLocalStorage)
|
||||||
s.Get("/", handleListStorages)
|
s.Get("/", handleListStorages)
|
||||||
s.Delete("/:id", handleDeleteStorage)
|
s.Delete("/:id", handleDeleteStorage)
|
||||||
|
s.Put("/:id/default", handleSetDefaultStorage)
|
||||||
}
|
}
|
||||||
|
@@ -28,6 +28,12 @@ type ServerConfig struct {
|
|||||||
ServerDescription string `json:"server_description"`
|
ServerDescription string `json:"server_description"`
|
||||||
// SiteInfo is an article that describes the site. It will be displayed on the home page. Markdown format.
|
// SiteInfo is an article that describes the site. It will be displayed on the home page. Markdown format.
|
||||||
SiteInfo string `json:"site_info"`
|
SiteInfo string `json:"site_info"`
|
||||||
|
// AllowNormalUserUpload indicates whether normal users are allowed to upload files.
|
||||||
|
AllowNormalUserUpload bool `json:"allow_normal_user_upload"`
|
||||||
|
// MaxNormalUserUploadSizeInMB is the maximum size of files that normal users can upload.
|
||||||
|
MaxNormalUserUploadSizeInMB int `json:"max_normal_user_upload_size_in_mb"`
|
||||||
|
// Prompt for upload page
|
||||||
|
UploadPrompt string `json:"upload_prompt"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -42,6 +48,9 @@ func init() {
|
|||||||
CloudflareTurnstileSecretKey: "",
|
CloudflareTurnstileSecretKey: "",
|
||||||
ServerName: "Nysoure",
|
ServerName: "Nysoure",
|
||||||
ServerDescription: "Nysoure is a file sharing service.",
|
ServerDescription: "Nysoure is a file sharing service.",
|
||||||
|
AllowNormalUserUpload: true,
|
||||||
|
MaxNormalUserUploadSizeInMB: 16,
|
||||||
|
UploadPrompt: "You can upload your files here.",
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
data, err := os.ReadFile(p)
|
data, err := os.ReadFile(p)
|
||||||
@@ -106,3 +115,15 @@ func CloudflareTurnstileSecretKey() string {
|
|||||||
func SiteInfo() string {
|
func SiteInfo() string {
|
||||||
return config.SiteInfo
|
return config.SiteInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AllowNormalUserUpload() bool {
|
||||||
|
return config.AllowNormalUserUpload
|
||||||
|
}
|
||||||
|
|
||||||
|
func MaxNormalUserUploadSize() int64 {
|
||||||
|
return int64(config.MaxNormalUserUploadSizeInMB) * 1024 * 1024
|
||||||
|
}
|
||||||
|
|
||||||
|
func UploadPrompt() string {
|
||||||
|
return config.UploadPrompt
|
||||||
|
}
|
||||||
|
@@ -1,9 +1,10 @@
|
|||||||
package dao
|
package dao
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"nysoure/server/model"
|
||||||
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"gorm.io/gorm/clause"
|
"gorm.io/gorm/clause"
|
||||||
"nysoure/server/model"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func CreateStorage(s model.Storage) (model.Storage, error) {
|
func CreateStorage(s model.Storage) (model.Storage, error) {
|
||||||
@@ -37,3 +38,12 @@ func AddStorageUsage(id uint, offset int64) error {
|
|||||||
return tx.Model(&model.Storage{}).Where("id = ?", id).Update("current_size", storage.CurrentSize+offset).Error
|
return tx.Model(&model.Storage{}).Where("id = ?", id).Update("current_size", storage.CurrentSize+offset).Error
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SetDefaultStorage(id uint) error {
|
||||||
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
|
if err := tx.Model(&model.Storage{}).Where("is_default = ?", true).Update("is_default", false).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return tx.Model(&model.Storage{}).Where("id = ?", id).Update("is_default", true).Error
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@@ -128,6 +128,8 @@ func serveIndexHtml(c fiber.Ctx) error {
|
|||||||
content = strings.ReplaceAll(content, "{{Url}}", url)
|
content = strings.ReplaceAll(content, "{{Url}}", url)
|
||||||
content = strings.ReplaceAll(content, "{{CFTurnstileSiteKey}}", cfTurnstileSiteKey)
|
content = strings.ReplaceAll(content, "{{CFTurnstileSiteKey}}", cfTurnstileSiteKey)
|
||||||
content = strings.ReplaceAll(content, "{{SiteInfo}}", siteInfo)
|
content = strings.ReplaceAll(content, "{{SiteInfo}}", siteInfo)
|
||||||
|
content = strings.ReplaceAll(content, "{{UploadPrompt}}", config.UploadPrompt())
|
||||||
|
content = strings.ReplaceAll(content, "{{AllowNormalUserUpload}}", strconv.FormatBool(config.AllowNormalUserUpload()))
|
||||||
|
|
||||||
c.Set("Content-Type", "text/html; charset=utf-8")
|
c.Set("Content-Type", "text/html; charset=utf-8")
|
||||||
return c.SendString(content)
|
return c.SendString(content)
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gorm.io/gorm"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Storage struct {
|
type Storage struct {
|
||||||
@@ -12,6 +13,7 @@ type Storage struct {
|
|||||||
Config string
|
Config string
|
||||||
MaxSize int64
|
MaxSize int64
|
||||||
CurrentSize int64
|
CurrentSize int64
|
||||||
|
IsDefault bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type StorageView struct {
|
type StorageView struct {
|
||||||
@@ -21,6 +23,7 @@ type StorageView struct {
|
|||||||
MaxSize int64 `json:"maxSize"`
|
MaxSize int64 `json:"maxSize"`
|
||||||
CurrentSize int64 `json:"currentSize"`
|
CurrentSize int64 `json:"currentSize"`
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
|
IsDefault bool `json:"isDefault"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Storage) ToView() StorageView {
|
func (s *Storage) ToView() StorageView {
|
||||||
@@ -31,5 +34,6 @@ func (s *Storage) ToView() StorageView {
|
|||||||
MaxSize: s.MaxSize,
|
MaxSize: s.MaxSize,
|
||||||
CurrentSize: s.CurrentSize,
|
CurrentSize: s.CurrentSize,
|
||||||
CreatedAt: s.CreatedAt,
|
CreatedAt: s.CreatedAt,
|
||||||
|
IsDefault: s.IsDefault,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -80,8 +80,10 @@ func CreateUploadingFile(uid uint, filename string, description string, fileSize
|
|||||||
return nil, model.NewInternalServerError("failed to check user permission")
|
return nil, model.NewInternalServerError("failed to check user permission")
|
||||||
}
|
}
|
||||||
if !canUpload {
|
if !canUpload {
|
||||||
|
if !config.AllowNormalUserUpload() || fileSize > config.MaxNormalUserUploadSize()*1024*1024 {
|
||||||
return nil, model.NewUnAuthorizedError("user cannot upload file")
|
return nil, model.NewUnAuthorizedError("user cannot upload file")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if fileSize > config.MaxFileSize() {
|
if fileSize > config.MaxFileSize() {
|
||||||
return nil, model.NewRequestError("file size exceeds the limit")
|
return nil, model.NewRequestError("file size exceeds the limit")
|
||||||
@@ -300,7 +302,7 @@ func CreateRedirectFile(uid uint, filename string, description string, resourceI
|
|||||||
log.Error("failed to check user permission: ", err)
|
log.Error("failed to check user permission: ", err)
|
||||||
return nil, model.NewInternalServerError("failed to check user permission")
|
return nil, model.NewInternalServerError("failed to check user permission")
|
||||||
}
|
}
|
||||||
if !canUpload {
|
if !canUpload && !config.AllowNormalUserUpload() {
|
||||||
return nil, model.NewUnAuthorizedError("user cannot upload file")
|
return nil, model.NewUnAuthorizedError("user cannot upload file")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -105,3 +105,19 @@ func DeleteStorage(uid, id uint) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SetDefaultStorage(uid, id uint) error {
|
||||||
|
isAdmin, err := CheckUserIsAdmin(uid)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("check user is admin failed: %s", err)
|
||||||
|
return model.NewInternalServerError("check user is admin failed")
|
||||||
|
}
|
||||||
|
if !isAdmin {
|
||||||
|
return model.NewUnAuthorizedError("only admin can set default storage")
|
||||||
|
}
|
||||||
|
err = dao.SetDefaultStorage(id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user