chore: support deleting storage (#1095)

This commit is contained in:
boojack 2023-02-15 22:54:46 +08:00 committed by GitHub
parent e46f77681d
commit 7e8011ba34
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 87 additions and 56 deletions

View File

@ -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
View File

@ -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
View File

@ -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=

View File

@ -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
}

View File

@ -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)

View File

@ -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
}
}

View File

@ -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,
}
}

View File

@ -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,
})

View File

@ -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 {

View File

@ -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

View File

@ -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>