mirror of
https://github.com/usememos/memos.git
synced 2025-02-12 01:10:38 +01:00
chore: support deleting storage (#1095)
This commit is contained in:
parent
e46f77681d
commit
7e8011ba34
@ -25,8 +25,8 @@ const (
|
||||
SystemSettingAdditionalScriptName SystemSettingName = "additionalScript"
|
||||
// SystemSettingCustomizedProfileName is the key type of customized server profile.
|
||||
SystemSettingCustomizedProfileName SystemSettingName = "customizedProfile"
|
||||
// SystemSettingStorageServiceID is the key type of sotrage service ID.
|
||||
SystemSettingStorageServiceID SystemSettingName = "storageServiceId"
|
||||
// SystemSettingStorageServiceIDName is the key type of storage service ID.
|
||||
SystemSettingStorageServiceIDName SystemSettingName = "storageServiceId"
|
||||
)
|
||||
|
||||
// CustomizedProfile is the struct definition for SystemSettingCustomizedProfileName system setting item.
|
||||
@ -61,7 +61,7 @@ func (key SystemSettingName) String() string {
|
||||
return "additionalScript"
|
||||
case SystemSettingCustomizedProfileName:
|
||||
return "customizedProfile"
|
||||
case SystemSettingStorageServiceID:
|
||||
case SystemSettingStorageServiceIDName:
|
||||
return "storageServiceId"
|
||||
}
|
||||
return ""
|
||||
@ -154,7 +154,12 @@ func (upsert SystemSettingUpsert) Validate() error {
|
||||
if !slices.Contains(UserSettingAppearanceValue, customizedProfile.Appearance) {
|
||||
return fmt.Errorf("invalid appearance value")
|
||||
}
|
||||
} else if upsert.Name == SystemSettingStorageServiceID {
|
||||
} else if upsert.Name == SystemSettingStorageServiceIDName {
|
||||
value := 0
|
||||
err := json.Unmarshal([]byte(upsert.Value), &value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to unmarshal system setting storage service id value")
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
return fmt.Errorf("invalid system setting name")
|
||||
@ -164,5 +169,5 @@ func (upsert SystemSettingUpsert) Validate() error {
|
||||
}
|
||||
|
||||
type SystemSettingFind struct {
|
||||
Name *SystemSettingName `json:"name"`
|
||||
Name SystemSettingName `json:"name"`
|
||||
}
|
||||
|
4
go.mod
4
go.mod
@ -25,7 +25,7 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.28 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.22 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.29 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.19 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.20 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.23 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.22 // indirect
|
||||
@ -63,7 +63,7 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.12
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.12
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.51
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.30.2
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.30.3
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/segmentio/analytics-go v3.1.0+incompatible
|
||||
github.com/stretchr/testify v1.8.0
|
||||
|
6
go.sum
6
go.sum
@ -16,8 +16,9 @@ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.22 h1:7AwGYXDdqRQYsluvKF
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.22/go.mod h1:EqK7gVrIGAHyZItrD1D8B0ilgwMD1GiWAmbU4u/JHNk=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.29 h1:J4xhFd6zHhdF9jPP0FQJ6WknzBboGMBNjKOv4iTuw4A=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.29/go.mod h1:TwuqRBGzxjQJIwH16/fOZodwXt2Zxa9/cwJC5ke4j7s=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.19 h1:FGvpyTg2LKEmMrLlpjOgkoNp9XF5CGeyAyo33LdqZW8=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.19/go.mod h1:8W88sW3PjamQpKFUQvHWWKay6ARsNvZnzU7+a4apubw=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.20 h1:YIvKIfPXQVp0EhXUV644kmQo6cQPPSRmC44A1HSoJeg=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.20/go.mod h1:8W88sW3PjamQpKFUQvHWWKay6ARsNvZnzU7+a4apubw=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 h1:y2+VQzC6Zh2ojtV2LoC0MNwHWc6qXv/j2vrQtlftkdA=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.23 h1:c5+bNdV8E4fIPteWx4HZSkqI07oY9exbfQ7JH7Yx4PI=
|
||||
@ -26,8 +27,9 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.22 h1:LjFQf8hFu
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.22/go.mod h1:xt0Au8yPIwYXf/GYPy/vl4K3CgwhfQMYbrH7DlUUIws=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.22 h1:ISLJ2BKXe4zzyZ7mp5ewKECiw0U7KpLgS3S6OxY9Cm0=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.22/go.mod h1:QFVbqK54XArazLvn2wvWMRBi/jGrWii46qbr5DyPGjc=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.30.2 h1:5EQWIFO+Hc8E2hFcXQJ1vm6ufl/PMt/6RVRDZRju2vM=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.30.2/go.mod h1:SXDHd6fI2RhqB7vmAzyYQCTQnpZrIprVJvYxpzW3JAM=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.30.3 h1:PVieHTwugdlHedlxLpYLQsOZAq736RScuEb/m4zhzc4=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.30.3/go.mod h1:XN3YcdmnWYZ3Hrnojvo5p2mc/wfF973nkq3ClXPDMHk=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.12.1 h1:lQKN/LNa3qqu2cDOQZybP7oL4nMGGiFqob0jZJaR8/4=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.12.1/go.mod h1:IgV8l3sj22nQDd5qcAGY0WenwCzCphqdbFOpfktZPrI=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.1 h1:0bLhH6DRAqox+g0LatcjGKjjhU6Eudyys6HB6DJVPj8=
|
||||
|
@ -45,7 +45,7 @@ func NewClient(ctx context.Context, storage *api.Storage) (*Client, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (client *Client) UploadFile(ctx context.Context, filename string, fileType string, src io.Reader, storage *api.Storage) (*string, error) {
|
||||
func (client *Client) UploadFile(ctx context.Context, filename string, fileType string, src io.Reader, storage *api.Storage) (string, error) {
|
||||
uploader := manager.NewUploader(client.Client)
|
||||
resp, err := uploader.Upload(ctx, &awss3.PutObjectInput{
|
||||
Bucket: aws.String(client.BucketName),
|
||||
@ -55,7 +55,7 @@ func (client *Client) UploadFile(ctx context.Context, filename string, fileType
|
||||
ACL: types.ObjectCannedACL(*aws.String("public-read")),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
var link string
|
||||
if storage.URLPrefix == "" {
|
||||
@ -63,5 +63,5 @@ func (client *Client) UploadFile(ctx context.Context, filename string, fileType
|
||||
} else {
|
||||
link = fmt.Sprintf("%s/%s", storage.URLPrefix, filename)
|
||||
}
|
||||
return &link, nil
|
||||
return link, nil
|
||||
}
|
||||
|
@ -81,9 +81,8 @@ func (s *Server) registerAuthRoutes(g *echo.Group) {
|
||||
// Change the default role to host if there is no host user.
|
||||
userCreate.Role = api.Host
|
||||
} else {
|
||||
systemSettingAllowSignUpName := api.SystemSettingAllowSignUpName
|
||||
allowSignUpSetting, err := s.Store.FindSystemSetting(ctx, &api.SystemSettingFind{
|
||||
Name: &systemSettingAllowSignUpName,
|
||||
Name: api.SystemSettingAllowSignUpName,
|
||||
})
|
||||
if err != nil && common.ErrorCode(err) != common.NotFound {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find system setting").SetInternal(err)
|
||||
|
@ -54,20 +54,19 @@ func (s *Server) registerMemoRoutes(g *echo.Group) {
|
||||
}
|
||||
|
||||
// Find system settings
|
||||
disablePublicMemosSystemSettingKey := api.SystemSettingDisablePublicMemosName
|
||||
disablePublicMemosSystemSetting, err := s.Store.FindSystemSetting(ctx, &api.SystemSettingFind{
|
||||
Name: &disablePublicMemosSystemSettingKey,
|
||||
Name: api.SystemSettingDisablePublicMemosName,
|
||||
})
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find system setting").SetInternal(err)
|
||||
}
|
||||
if disablePublicMemosSystemSetting != nil {
|
||||
disablePublicMemosValue := false
|
||||
err = json.Unmarshal([]byte(disablePublicMemosSystemSetting.Value), &disablePublicMemosValue)
|
||||
disablePublicMemos := false
|
||||
err = json.Unmarshal([]byte(disablePublicMemosSystemSetting.Value), &disablePublicMemos)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to unmarshal system setting").SetInternal(err)
|
||||
}
|
||||
if disablePublicMemosValue {
|
||||
if disablePublicMemos {
|
||||
memoCreate.Visibility = api.Private
|
||||
}
|
||||
}
|
||||
|
@ -85,26 +85,20 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
|
||||
}
|
||||
defer src.Close()
|
||||
|
||||
var resourceCreate *api.ResourceCreate
|
||||
systemSettingStorageServiceName := api.SystemSettingStorageServiceID
|
||||
systemSetting, err := s.Store.FindSystemSetting(ctx, &api.SystemSettingFind{Name: &systemSettingStorageServiceName})
|
||||
systemSetting, err := s.Store.FindSystemSetting(ctx, &api.SystemSettingFind{Name: api.SystemSettingStorageServiceIDName})
|
||||
if err != nil && common.ErrorCode(err) != common.NotFound {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find storage").SetInternal(err)
|
||||
}
|
||||
storeLocal := false
|
||||
if common.ErrorCode(err) == common.NotFound {
|
||||
storeLocal = true
|
||||
} else {
|
||||
var value int
|
||||
err = json.Unmarshal([]byte(systemSetting.Value), &value)
|
||||
storageServiceID := 0
|
||||
if systemSetting != nil {
|
||||
err = json.Unmarshal([]byte(systemSetting.Value), &storageServiceID)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to unmarshal storage service id").SetInternal(err)
|
||||
}
|
||||
if value == 0 {
|
||||
storeLocal = true
|
||||
}
|
||||
}
|
||||
if storeLocal {
|
||||
|
||||
var resourceCreate *api.ResourceCreate
|
||||
if storageServiceID == 0 {
|
||||
fileBytes, err := io.ReadAll(src)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to read file").SetInternal(err)
|
||||
@ -117,12 +111,7 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
|
||||
Blob: fileBytes,
|
||||
}
|
||||
} else {
|
||||
storageID, err := strconv.Atoi(systemSetting.Value)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to convert storageID").SetInternal(err)
|
||||
}
|
||||
|
||||
storage, err := s.Store.FindStorage(ctx, &api.StorageFind{ID: &storageID})
|
||||
storage, err := s.Store.FindStorage(ctx, &api.StorageFind{ID: &storageServiceID})
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find storage").SetInternal(err)
|
||||
}
|
||||
@ -136,12 +125,11 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to upload via s3 client").SetInternal(err)
|
||||
}
|
||||
|
||||
resourceCreate = &api.ResourceCreate{
|
||||
CreatorID: userID,
|
||||
Filename: filename,
|
||||
Type: filetype,
|
||||
ExternalLink: *link,
|
||||
ExternalLink: link,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,6 +117,21 @@ func (s *Server) registerStorageRoutes(g *echo.Group) {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("ID is not a number: %s", c.Param("storageId"))).SetInternal(err)
|
||||
}
|
||||
|
||||
systemSetting, err := s.Store.FindSystemSetting(ctx, &api.SystemSettingFind{Name: api.SystemSettingStorageServiceIDName})
|
||||
if err != nil && common.ErrorCode(err) != common.NotFound {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find storage").SetInternal(err)
|
||||
}
|
||||
if systemSetting != nil {
|
||||
storageServiceID := 0
|
||||
err = json.Unmarshal([]byte(systemSetting.Value), &storageServiceID)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to unmarshal storage service id").SetInternal(err)
|
||||
}
|
||||
if storageServiceID == storageID {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Storage service %d is using", storageID))
|
||||
}
|
||||
}
|
||||
|
||||
storage, err := s.Store.FindStorage(ctx, &api.StorageFind{
|
||||
ID: &storageID,
|
||||
})
|
||||
|
@ -104,8 +104,8 @@ func (s *Server) registerSystemRoutes(g *echo.Group) {
|
||||
if v := valueMap["externalUrl"]; v != nil {
|
||||
systemStatus.CustomizedProfile.ExternalURL = v.(string)
|
||||
}
|
||||
} else if systemSetting.Name == api.SystemSettingStorageServiceID {
|
||||
systemStatus.StorageServiceID = int(value.(float64))
|
||||
} else if systemSetting.Name == api.SystemSettingStorageServiceIDName {
|
||||
systemStatus.StorageServiceID = value.(int)
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,16 +209,15 @@ func (s *Server) registerSystemRoutes(g *echo.Group) {
|
||||
}
|
||||
|
||||
func (s *Server) getSystemServerID(ctx context.Context) (string, error) {
|
||||
serverIDKey := api.SystemSettingServerID
|
||||
serverIDValue, err := s.Store.FindSystemSetting(ctx, &api.SystemSettingFind{
|
||||
Name: &serverIDKey,
|
||||
Name: api.SystemSettingServerID,
|
||||
})
|
||||
if err != nil && common.ErrorCode(err) != common.NotFound {
|
||||
return "", err
|
||||
}
|
||||
if serverIDValue == nil || serverIDValue.Value == "" {
|
||||
serverIDValue, err = s.Store.UpsertSystemSetting(ctx, &api.SystemSettingUpsert{
|
||||
Name: serverIDKey,
|
||||
Name: api.SystemSettingServerID,
|
||||
Value: uuid.NewString(),
|
||||
})
|
||||
if err != nil {
|
||||
@ -229,16 +228,15 @@ func (s *Server) getSystemServerID(ctx context.Context) (string, error) {
|
||||
}
|
||||
|
||||
func (s *Server) getSystemSecretSessionName(ctx context.Context) (string, error) {
|
||||
secretSessionNameKey := api.SystemSettingSecretSessionName
|
||||
secretSessionNameValue, err := s.Store.FindSystemSetting(ctx, &api.SystemSettingFind{
|
||||
Name: &secretSessionNameKey,
|
||||
Name: api.SystemSettingSecretSessionName,
|
||||
})
|
||||
if err != nil && common.ErrorCode(err) != common.NotFound {
|
||||
return "", err
|
||||
}
|
||||
if secretSessionNameValue == nil || secretSessionNameValue.Value == "" {
|
||||
secretSessionNameValue, err = s.Store.UpsertSystemSetting(ctx, &api.SystemSettingUpsert{
|
||||
Name: secretSessionNameKey,
|
||||
Name: api.SystemSettingSecretSessionName,
|
||||
Value: uuid.NewString(),
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -114,10 +114,7 @@ func upsertSystemSetting(ctx context.Context, tx *sql.Tx, upsert *api.SystemSett
|
||||
|
||||
func findSystemSettingList(ctx context.Context, tx *sql.Tx, find *api.SystemSettingFind) ([]*systemSettingRaw, error) {
|
||||
where, args := []string{"1 = 1"}, []interface{}{}
|
||||
|
||||
if v := find.Name; v != nil {
|
||||
where, args = append(where, "name = ?"), append(args, v.String())
|
||||
}
|
||||
where, args = append(where, "name = ?"), append(args, find.Name.String())
|
||||
|
||||
query := `
|
||||
SELECT
|
||||
|
@ -1,10 +1,11 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import Icon from "./Icon";
|
||||
import { generateDialog } from "./Dialog";
|
||||
import { Button, Input, Typography } from "@mui/joy";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Button, Input, Typography } from "@mui/joy";
|
||||
import { useStorageStore } from "../store/module";
|
||||
import { generateDialog } from "./Dialog";
|
||||
import Icon from "./Icon";
|
||||
import toastHelper from "./Toast";
|
||||
import { showCommonDialog } from "./Dialog/CommonDialog";
|
||||
|
||||
interface Props extends DialogProps {
|
||||
storage?: Storage;
|
||||
@ -66,6 +67,28 @@ const CreateStorageServiceDialog: React.FC<Props> = (props: Props) => {
|
||||
destroy();
|
||||
};
|
||||
|
||||
const handleDeleteBtnClick = async () => {
|
||||
if (isCreating) {
|
||||
return;
|
||||
}
|
||||
|
||||
showCommonDialog({
|
||||
title: t("setting.storage-section.delete-storage"),
|
||||
content: t("setting.storage-section.warning-text"),
|
||||
style: "warning",
|
||||
dialogName: "delete-storage-dialog",
|
||||
onConfirm: async () => {
|
||||
try {
|
||||
await storageStore.deleteStorageById(storage.id);
|
||||
} catch (error: any) {
|
||||
console.error(error);
|
||||
toastHelper.error(error.response.data.message);
|
||||
}
|
||||
destroy();
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const handleNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const name = event.target.value;
|
||||
setStorageCreate({
|
||||
@ -165,6 +188,11 @@ const CreateStorageServiceDialog: React.FC<Props> = (props: Props) => {
|
||||
<Button variant="plain" color="neutral" onClick={handleCloseBtnClick}>
|
||||
Cancel
|
||||
</Button>
|
||||
{!isCreating && (
|
||||
<Button color="danger" onClick={handleDeleteBtnClick}>
|
||||
Delete
|
||||
</Button>
|
||||
)}
|
||||
<Button onClick={handleConfirmBtnClick} disabled={!allowConfirmAction()}>
|
||||
{isCreating ? "Create" : "Update"}
|
||||
</Button>
|
||||
|
Loading…
x
Reference in New Issue
Block a user