chore: remove resource public id (#1912)

* chore: remove resource public id

* chore: update
This commit is contained in:
boojack 2023-07-08 11:29:50 +08:00 committed by GitHub
parent 2157651d17
commit 7e391bd53d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 82 additions and 93 deletions

View File

@ -8,10 +8,10 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/usememos/memos/api/v1/auth"
"github.com/usememos/memos/common/util" "github.com/usememos/memos/common/util"
"github.com/usememos/memos/plugin/idp" "github.com/usememos/memos/plugin/idp"
"github.com/usememos/memos/plugin/idp/oauth2" "github.com/usememos/memos/plugin/idp/oauth2"
"github.com/usememos/memos/server/auth"
"github.com/usememos/memos/store" "github.com/usememos/memos/store"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )

View File

@ -10,8 +10,8 @@ import (
"github.com/golang-jwt/jwt/v4" "github.com/golang-jwt/jwt/v4"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/usememos/memos/api/v1/auth"
"github.com/usememos/memos/common/util" "github.com/usememos/memos/common/util"
"github.com/usememos/memos/server/auth"
"github.com/usememos/memos/store" "github.com/usememos/memos/store"
) )

View File

@ -43,7 +43,6 @@ type Resource struct {
ExternalLink string `json:"externalLink"` ExternalLink string `json:"externalLink"`
Type string `json:"type"` Type string `json:"type"`
Size int64 `json:"size"` Size int64 `json:"size"`
PublicID string `json:"publicId"`
// Related fields // Related fields
LinkedMemoAmount int `json:"linkedMemoAmount"` LinkedMemoAmount int `json:"linkedMemoAmount"`
@ -54,7 +53,6 @@ type CreateResourceRequest struct {
InternalPath string `json:"internalPath"` InternalPath string `json:"internalPath"`
ExternalLink string `json:"externalLink"` ExternalLink string `json:"externalLink"`
Type string `json:"type"` Type string `json:"type"`
PublicID string `json:"publicId"`
DownloadToLocal bool `json:"downloadToLocal"` DownloadToLocal bool `json:"downloadToLocal"`
} }
@ -62,12 +60,10 @@ type FindResourceRequest struct {
ID *int `json:"id"` ID *int `json:"id"`
CreatorID *int `json:"creatorId"` CreatorID *int `json:"creatorId"`
Filename *string `json:"filename"` Filename *string `json:"filename"`
PublicID *string `json:"publicId"`
} }
type UpdateResourceRequest struct { type UpdateResourceRequest struct {
Filename *string `json:"filename"` Filename *string `json:"filename"`
ResetPublicID *bool `json:"resetPublicId"`
} }
const ( const (
@ -101,7 +97,6 @@ func (s *APIV1Service) registerResourceRoutes(g *echo.Group) {
Filename: request.Filename, Filename: request.Filename,
ExternalLink: request.ExternalLink, ExternalLink: request.ExternalLink,
Type: request.Type, Type: request.Type,
PublicID: util.GenUUID(),
} }
if request.ExternalLink != "" { if request.ExternalLink != "" {
// Only allow those external links scheme with http/https // Only allow those external links scheme with http/https
@ -195,7 +190,6 @@ func (s *APIV1Service) registerResourceRoutes(g *echo.Group) {
} }
defer sourceFile.Close() defer sourceFile.Close()
create := &store.Resource{}
systemSettingStorageServiceID, err := s.Store.GetSystemSetting(ctx, &store.FindSystemSetting{Name: SystemSettingStorageServiceIDName.String()}) systemSettingStorageServiceID, err := s.Store.GetSystemSetting(ctx, &store.FindSystemSetting{Name: SystemSettingStorageServiceIDName.String()})
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find storage").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find storage").SetInternal(err)
@ -208,7 +202,7 @@ func (s *APIV1Service) registerResourceRoutes(g *echo.Group) {
} }
} }
publicID := util.GenUUID() var create *store.Resource
if storageServiceID == DatabaseStorage { if storageServiceID == DatabaseStorage {
fileBytes, err := io.ReadAll(sourceFile) fileBytes, err := io.ReadAll(sourceFile)
if err != nil { if err != nil {
@ -229,7 +223,7 @@ func (s *APIV1Service) registerResourceRoutes(g *echo.Group) {
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find local storage path setting").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find local storage path setting").SetInternal(err)
} }
localStoragePath := "assets/{publicid}" localStoragePath := "assets/{filename}"
if systemSettingLocalStoragePath != nil && systemSettingLocalStoragePath.Value != "" { if systemSettingLocalStoragePath != nil && systemSettingLocalStoragePath.Value != "" {
err = json.Unmarshal([]byte(systemSettingLocalStoragePath.Value), &localStoragePath) err = json.Unmarshal([]byte(systemSettingLocalStoragePath.Value), &localStoragePath)
if err != nil { if err != nil {
@ -237,10 +231,10 @@ func (s *APIV1Service) registerResourceRoutes(g *echo.Group) {
} }
} }
filePath := filepath.FromSlash(localStoragePath) filePath := filepath.FromSlash(localStoragePath)
if !strings.Contains(filePath, "{publicid}") { if !strings.Contains(filePath, "{filename}") {
filePath = filepath.Join(filePath, "{publicid}") filePath = filepath.Join(filePath, "{filename}")
} }
filePath = filepath.Join(s.Profile.Data, replacePathTemplate(filePath, file.Filename, publicID+filepath.Ext(file.Filename))) filePath = filepath.Join(s.Profile.Data, replacePathTemplate(filePath, file.Filename))
dir := filepath.Dir(filePath) dir := filepath.Dir(filePath)
if err = os.MkdirAll(dir, os.ModePerm); err != nil { if err = os.MkdirAll(dir, os.ModePerm); err != nil {
@ -292,10 +286,10 @@ func (s *APIV1Service) registerResourceRoutes(g *echo.Group) {
} }
filePath := s3Config.Path filePath := s3Config.Path
if !strings.Contains(filePath, "{publicid}") { if !strings.Contains(filePath, "{filename}") {
filePath = path.Join(filePath, "{publicid}") filePath = path.Join(filePath, "{filename}")
} }
filePath = replacePathTemplate(filePath, file.Filename, publicID+filepath.Ext(file.Filename)) filePath = replacePathTemplate(filePath, file.Filename)
_, filename := filepath.Split(filePath) _, filename := filepath.Split(filePath)
link, err := s3Client.UploadFile(ctx, filePath, filetype, sourceFile) link, err := s3Client.UploadFile(ctx, filePath, filetype, sourceFile)
if err != nil { if err != nil {
@ -313,7 +307,6 @@ func (s *APIV1Service) registerResourceRoutes(g *echo.Group) {
} }
} }
create.PublicID = publicID
resource, err := s.Store.CreateResource(ctx, create) resource, err := s.Store.CreateResource(ctx, create)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create resource").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create resource").SetInternal(err)
@ -389,10 +382,6 @@ func (s *APIV1Service) registerResourceRoutes(g *echo.Group) {
if request.Filename != nil && *request.Filename != "" { if request.Filename != nil && *request.Filename != "" {
update.Filename = request.Filename update.Filename = request.Filename
} }
if request.ResetPublicID != nil && *request.ResetPublicID {
publicID := util.GenUUID()
update.PublicID = &publicID
}
resource, err = s.Store.UpdateResource(ctx, update) resource, err = s.Store.UpdateResource(ctx, update)
if err != nil { if err != nil {
@ -431,7 +420,7 @@ func (s *APIV1Service) registerResourceRoutes(g *echo.Group) {
} }
ext := filepath.Ext(resource.Filename) ext := filepath.Ext(resource.Filename)
thumbnailPath := path.Join(s.Profile.Data, thumbnailImagePath, fmt.Sprintf("%d-%s%s", resource.ID, resource.PublicID, ext)) thumbnailPath := path.Join(s.Profile.Data, thumbnailImagePath, fmt.Sprintf("%d%s", resource.ID, ext))
if err := os.Remove(thumbnailPath); err != nil { if err := os.Remove(thumbnailPath); err != nil {
log.Warn(fmt.Sprintf("failed to delete local thumbnail with path %s", thumbnailPath), zap.Error(err)) log.Warn(fmt.Sprintf("failed to delete local thumbnail with path %s", thumbnailPath), zap.Error(err))
} }
@ -496,7 +485,7 @@ func (s *APIV1Service) registerResourcePublicRoutes(g *echo.Group) {
if c.QueryParam("thumbnail") == "1" && util.HasPrefixes(resource.Type, "image/png", "image/jpeg") { if c.QueryParam("thumbnail") == "1" && util.HasPrefixes(resource.Type, "image/png", "image/jpeg") {
ext := filepath.Ext(resource.Filename) ext := filepath.Ext(resource.Filename)
thumbnailPath := path.Join(s.Profile.Data, thumbnailImagePath, fmt.Sprintf("%d-%s%s", resource.ID, resource.PublicID, ext)) thumbnailPath := path.Join(s.Profile.Data, thumbnailImagePath, fmt.Sprintf("%d%s", resource.ID, ext))
thumbnailBlob, err := getOrGenerateThumbnailImage(blob, thumbnailPath) thumbnailBlob, err := getOrGenerateThumbnailImage(blob, thumbnailPath)
if err != nil { if err != nil {
log.Warn(fmt.Sprintf("failed to get or generate local thumbnail with path %s", thumbnailPath), zap.Error(err)) log.Warn(fmt.Sprintf("failed to get or generate local thumbnail with path %s", thumbnailPath), zap.Error(err))
@ -516,8 +505,8 @@ func (s *APIV1Service) registerResourcePublicRoutes(g *echo.Group) {
} }
return c.Stream(http.StatusOK, resourceType, bytes.NewReader(blob)) return c.Stream(http.StatusOK, resourceType, bytes.NewReader(blob))
} }
g.GET("/r/:resourceId", f) g.GET("/r/:resourceId", f)
g.GET("/r/:resourceId/", f)
g.GET("/r/:resourceId/*", f) g.GET("/r/:resourceId/*", f)
} }
@ -543,12 +532,10 @@ func (s *APIV1Service) createResourceCreateActivity(ctx context.Context, resourc
return err return err
} }
func replacePathTemplate(path, filename, publicID string) string { func replacePathTemplate(path, filename string) string {
t := time.Now() t := time.Now()
path = fileKeyPattern.ReplaceAllStringFunc(path, func(s string) string { path = fileKeyPattern.ReplaceAllStringFunc(path, func(s string) string {
switch s { switch s {
case "{publicid}":
return publicID
case "{filename}": case "{filename}":
return filename return filename
case "{timestamp}": case "{timestamp}":
@ -624,7 +611,7 @@ func checkResourceVisibility(ctx context.Context, s *store.Store, resourceID int
return store.Private, err return store.Private, err
} }
// If resource is belongs to no memo, it'll always PRIVATE // If resource is belongs to no memo, it'll always PRIVATE.
if len(memoResources) == 0 { if len(memoResources) == 0 {
return store.Private, nil return store.Private, nil
} }
@ -640,7 +627,7 @@ func checkResourceVisibility(ctx context.Context, s *store.Store, resourceID int
var isProtected bool var isProtected bool
for _, visibility := range visibilityList { for _, visibility := range visibilityList {
// If any memo is PUBLIC, resource do // If any memo is PUBLIC, resource should be PUBLIC too.
if visibility == store.Public { if visibility == store.Public {
return store.Public, nil return store.Public, nil
} }
@ -650,12 +637,10 @@ func checkResourceVisibility(ctx context.Context, s *store.Store, resourceID int
} }
} }
// If no memo is PUBLIC, but any memo is PROTECTED, resource do
if isProtected { if isProtected {
return store.Protected, nil return store.Protected, nil
} }
// If all memo is PRIVATE, the resource do
return store.Private, nil return store.Private, nil
} }
@ -671,7 +656,6 @@ func convertResourceFromStore(resource *store.Resource) *Resource {
ExternalLink: resource.ExternalLink, ExternalLink: resource.ExternalLink,
Type: resource.Type, Type: resource.Type,
Size: resource.Size, Size: resource.Size,
PublicID: resource.PublicID,
LinkedMemoAmount: resource.LinkedMemoAmount, LinkedMemoAmount: resource.LinkedMemoAmount,
} }
} }

View File

@ -114,7 +114,7 @@ func (s *APIV1Service) generateRSSFromMemoList(ctx context.Context, memoList []*
if resource.ExternalLink != "" { if resource.ExternalLink != "" {
enclosure.Url = resource.ExternalLink enclosure.Url = resource.ExternalLink
} else { } else {
enclosure.Url = baseURL + "/o/r/" + strconv.Itoa(resource.ID) + "/" + resource.PublicID + "/" + resource.Filename enclosure.Url = baseURL + "/o/r/" + strconv.Itoa(resource.ID)
} }
enclosure.Length = strconv.Itoa(int(resource.Size)) enclosure.Length = strconv.Itoa(int(resource.Size))
enclosure.Type = resource.Type enclosure.Type = resource.Type

View File

@ -9,7 +9,6 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
apiv1 "github.com/usememos/memos/api/v1" apiv1 "github.com/usememos/memos/api/v1"
"github.com/usememos/memos/common/util"
"github.com/usememos/memos/plugin/telegram" "github.com/usememos/memos/plugin/telegram"
"github.com/usememos/memos/store" "github.com/usememos/memos/store"
) )
@ -94,7 +93,6 @@ func (t *telegramHandler) MessageHandle(ctx context.Context, bot *telegram.Bot,
Type: mime, Type: mime,
Size: int64(len(blob)), Size: int64(len(blob)),
Blob: blob, Blob: blob,
PublicID: util.GenUUID(),
}) })
if err != nil { if err != nil {
_, err := bot.EditMessage(ctx, message.Chat.ID, reply.MessageID, fmt.Sprintf("failed to CreateResource: %s", err), nil) _, err := bot.EditMessage(ctx, message.Chat.ID, reply.MessageID, fmt.Sprintf("failed to CreateResource: %s", err), nil)

View File

@ -76,9 +76,7 @@ CREATE TABLE resource (
external_link TEXT NOT NULL DEFAULT '', external_link TEXT NOT NULL DEFAULT '',
type TEXT NOT NULL DEFAULT '', type TEXT NOT NULL DEFAULT '',
size INTEGER NOT NULL DEFAULT 0, size INTEGER NOT NULL DEFAULT 0,
internal_path TEXT NOT NULL DEFAULT '', internal_path TEXT NOT NULL DEFAULT ''
public_id TEXT NOT NULL DEFAULT '',
UNIQUE(id, public_id)
); );
-- memo_resource -- memo_resource

View File

@ -0,0 +1,25 @@
DROP TABLE IF EXISTS resource_temp;
CREATE TABLE resource_temp (
id INTEGER PRIMARY KEY AUTOINCREMENT,
creator_id INTEGER NOT NULL,
created_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
updated_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
filename TEXT NOT NULL DEFAULT '',
blob BLOB DEFAULT NULL,
external_link TEXT NOT NULL DEFAULT '',
type TEXT NOT NULL DEFAULT '',
size INTEGER NOT NULL DEFAULT 0,
internal_path TEXT NOT NULL DEFAULT ''
);
INSERT INTO
resource_temp (id, creator_id, created_ts, updated_ts, filename, blob, external_link, type, size, internal_path)
SELECT
id, creator_id, created_ts, updated_ts, filename, blob, external_link, type, size, internal_path
FROM
resource;
DROP TABLE resource;
ALTER TABLE resource_temp RENAME TO resource;

View File

@ -76,9 +76,7 @@ CREATE TABLE resource (
external_link TEXT NOT NULL DEFAULT '', external_link TEXT NOT NULL DEFAULT '',
type TEXT NOT NULL DEFAULT '', type TEXT NOT NULL DEFAULT '',
size INTEGER NOT NULL DEFAULT 0, size INTEGER NOT NULL DEFAULT 0,
internal_path TEXT NOT NULL DEFAULT '', internal_path TEXT NOT NULL DEFAULT ''
public_id TEXT NOT NULL DEFAULT '',
UNIQUE(id, public_id)
); );
-- memo_resource -- memo_resource

View File

@ -22,7 +22,6 @@ type Resource struct {
ExternalLink string ExternalLink string
Type string Type string
Size int64 Size int64
PublicID string
LinkedMemoAmount int LinkedMemoAmount int
} }
@ -32,7 +31,6 @@ type FindResource struct {
CreatorID *int CreatorID *int
Filename *string Filename *string
MemoID *int MemoID *int
PublicID *string
Limit *int Limit *int
Offset *int Offset *int
} }
@ -41,7 +39,6 @@ type UpdateResource struct {
ID int ID int
UpdatedTs *int64 UpdatedTs *int64
Filename *string Filename *string
PublicID *string
} }
type DeleteResource struct { type DeleteResource struct {
@ -63,13 +60,12 @@ func (s *Store) CreateResource(ctx context.Context, create *Resource) (*Resource
type, type,
size, size,
creator_id, creator_id,
internal_path, internal_path
public_id
) )
VALUES (?, ?, ?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?, ?)
RETURNING id, created_ts, updated_ts RETURNING id, created_ts, updated_ts
`, `,
create.Filename, create.Blob, create.ExternalLink, create.Type, create.Size, create.CreatorID, create.InternalPath, create.PublicID, create.Filename, create.Blob, create.ExternalLink, create.Type, create.Size, create.CreatorID, create.InternalPath,
).Scan(&create.ID, &create.CreatedTs, &create.UpdatedTs); err != nil { ).Scan(&create.ID, &create.CreatedTs, &create.UpdatedTs); err != nil {
return nil, err return nil, err
} }
@ -98,10 +94,6 @@ func (s *Store) ListResources(ctx context.Context, find *FindResource) ([]*Resou
return nil, err return nil, err
} }
if err := tx.Commit(); err != nil {
return nil, err
}
return resources, nil return resources, nil
} }
@ -143,12 +135,9 @@ func (s *Store) UpdateResource(ctx context.Context, update *UpdateResource) (*Re
if v := update.Filename; v != nil { if v := update.Filename; v != nil {
set, args = append(set, "filename = ?"), append(args, *v) set, args = append(set, "filename = ?"), append(args, *v)
} }
if v := update.PublicID; v != nil {
set, args = append(set, "public_id = ?"), append(args, *v)
}
args = append(args, update.ID) args = append(args, update.ID)
fields := []string{"id", "filename", "external_link", "type", "size", "creator_id", "created_ts", "updated_ts", "internal_path", "public_id"} fields := []string{"id", "filename", "external_link", "type", "size", "creator_id", "created_ts", "updated_ts", "internal_path"}
query := ` query := `
UPDATE resource UPDATE resource
SET ` + strings.Join(set, ", ") + ` SET ` + strings.Join(set, ", ") + `
@ -165,7 +154,6 @@ func (s *Store) UpdateResource(ctx context.Context, update *UpdateResource) (*Re
&resource.CreatedTs, &resource.CreatedTs,
&resource.UpdatedTs, &resource.UpdatedTs,
&resource.InternalPath, &resource.InternalPath,
&resource.PublicID,
} }
if err := tx.QueryRowContext(ctx, query, args...).Scan(dests...); err != nil { if err := tx.QueryRowContext(ctx, query, args...).Scan(dests...); err != nil {
return nil, err return nil, err
@ -215,11 +203,8 @@ func listResources(ctx context.Context, tx *sql.Tx, find *FindResource) ([]*Reso
if v := find.MemoID; v != nil { if v := find.MemoID; v != nil {
where, args = append(where, "resource.id in (SELECT resource_id FROM memo_resource WHERE memo_id = ?)"), append(args, *v) where, args = append(where, "resource.id in (SELECT resource_id FROM memo_resource WHERE memo_id = ?)"), append(args, *v)
} }
if v := find.PublicID; v != nil {
where, args = append(where, "resource.public_id = ?"), append(args, *v)
}
fields := []string{"resource.id", "resource.filename", "resource.external_link", "resource.type", "resource.size", "resource.creator_id", "resource.created_ts", "resource.updated_ts", "internal_path", "public_id"} fields := []string{"resource.id", "resource.filename", "resource.external_link", "resource.type", "resource.size", "resource.creator_id", "resource.created_ts", "resource.updated_ts", "internal_path"}
if find.GetBlob { if find.GetBlob {
fields = append(fields, "resource.blob") fields = append(fields, "resource.blob")
} }
@ -261,7 +246,6 @@ func listResources(ctx context.Context, tx *sql.Tx, find *FindResource) ([]*Reso
&resource.CreatedTs, &resource.CreatedTs,
&resource.UpdatedTs, &resource.UpdatedTs,
&resource.InternalPath, &resource.InternalPath,
&resource.PublicID,
} }
if find.GetBlob { if find.GetBlob {
dests = append(dests, &resource.Blob) dests = append(dests, &resource.Blob)

View File

@ -19,7 +19,6 @@ func TestResourceStore(t *testing.T) {
ExternalLink: "", ExternalLink: "",
Type: "application/epub+zip", Type: "application/epub+zip",
Size: 637607, Size: 637607,
PublicID: "a02748e2-9b56-46b2-8b1f-72d686d52f77",
}) })
require.NoError(t, err) require.NoError(t, err)

View File

@ -0,0 +1,26 @@
import { Tooltip } from "@mui/joy";
import Icon from "./Icon";
import { useTranslation } from "react-i18next";
interface Props {
className?: string;
url: string;
title?: string;
}
const LearnMore: React.FC<Props> = (props: Props) => {
const { className, url, title } = props;
const { t } = useTranslation();
return (
<>
<Tooltip title={title ?? t("common.learn-more")} placement="top">
<a className={`text-gray-500 dark:text-gray-400 hover:text-blue-600 ${className}`} href={url} target="_blank">
<Icon.ExternalLink className="w-4 h-auto" />
</a>
</Tooltip>
</>
);
};
export default LearnMore;

View File

@ -37,21 +37,6 @@ const ResourceItemDropdown = ({ resource }: Props) => {
toast.success(t("message.succeed-copy-resource-link")); toast.success(t("message.succeed-copy-resource-link"));
}; };
const handleResetResourceLinkBtnClick = (resource: Resource) => {
showCommonDialog({
title: t("resource.reset-resource-link"),
content: t("resource.reset-link-prompt"),
style: "warning",
dialogName: "reset-resource-link-dialog",
onConfirm: async () => {
await resourceStore.patchResource({
id: resource.id,
resetPublicId: true,
});
},
});
};
const handleRenameBtnClick = (resource: Resource) => { const handleRenameBtnClick = (resource: Resource) => {
showChangeResourceFilenameDialog(resource.id, resource.filename); showChangeResourceFilenameDialog(resource.id, resource.filename);
}; };
@ -91,12 +76,6 @@ const ResourceItemDropdown = ({ resource }: Props) => {
> >
{t("resource.copy-link")} {t("resource.copy-link")}
</button> </button>
<button
className="w-full text-left text-sm leading-6 py-1 px-3 cursor-pointer rounded hover:bg-gray-100 dark:hover:bg-zinc-600"
onClick={() => handleResetResourceLinkBtnClick(resource)}
>
{t("resource.reset-link")}
</button>
<button <button
className="w-full text-left text-sm leading-6 py-1 px-3 cursor-pointer rounded hover:bg-gray-100 dark:hover:bg-zinc-600" className="w-full text-left text-sm leading-6 py-1 px-3 cursor-pointer rounded hover:bg-gray-100 dark:hover:bg-zinc-600"
onClick={() => handleRenameBtnClick(resource)} onClick={() => handleRenameBtnClick(resource)}

View File

@ -1,12 +1,12 @@
import { Button, Input } from "@mui/joy"; import { Button, Input } from "@mui/joy";
import { useState } from "react"; import { useState } from "react";
import { useTranslation } from "react-i18next";
import { toast } from "react-hot-toast"; import { toast } from "react-hot-toast";
import { useGlobalStore } from "@/store/module"; import { useGlobalStore } from "@/store/module";
import * as api from "@/helpers/api"; import * as api from "@/helpers/api";
import { generateDialog } from "./Dialog"; import { generateDialog } from "./Dialog";
import Icon from "./Icon"; import Icon from "./Icon";
import HelpButton from "./kit/HelpButton"; import LearnMore from "./LearnMore";
import { useTranslation } from "react-i18next";
interface Props extends DialogProps { interface Props extends DialogProps {
localStoragePath?: string; localStoragePath?: string;
@ -51,8 +51,8 @@ const UpdateLocalStorageDialog: React.FC<Props> = (props: Props) => {
<div className="dialog-content-container max-w-xs"> <div className="dialog-content-container max-w-xs">
<p className="text-sm break-words mb-1">{t("setting.storage-section.update-local-path-description")}</p> <p className="text-sm break-words mb-1">{t("setting.storage-section.update-local-path-description")}</p>
<div className="flex flex-row"> <div className="flex flex-row">
<p className="text-sm text-gray-400 mb-2 break-all">e.g. {"assets/{publicid}"}</p> <p className="text-sm text-gray-400 mb-2 break-all">e.g. {"assets/{filename}"}</p>
<HelpButton hint={t("common.learn-more")} url="https://usememos.com/docs/local-storage" /> <LearnMore url="https://usememos.com/docs/local-storage" />
</div> </div>
<Input <Input
className="mb-2" className="mb-2"

View File

@ -214,7 +214,7 @@ const ResourcesDashboard = () => {
<div className="w-full flex flex-col justify-start items-start px-4 py-3 rounded-xl bg-white dark:bg-zinc-700 text-black dark:text-gray-300"> <div className="w-full flex flex-col justify-start items-start px-4 py-3 rounded-xl bg-white dark:bg-zinc-700 text-black dark:text-gray-300">
<div className="relative w-full flex flex-row justify-between items-center"> <div className="relative w-full flex flex-row justify-between items-center">
<p className="flex flex-row justify-start items-center select-none rounded"> <p className="flex flex-row justify-start items-center select-none rounded">
<Icon.Paperclip className="w-5 h-auto mr-1" /> {t("common.resources")} <Icon.Paperclip className="w-5 h-auto mr-1 ml-2" /> {t("common.resources")}
</p> </p>
<ResourceSearchBar setQuery={handleSearchResourceInputChange} /> <ResourceSearchBar setQuery={handleSearchResourceInputChange} />
</div> </div>

View File

@ -10,7 +10,6 @@ interface Resource {
externalLink: string; externalLink: string;
type: string; type: string;
size: string; size: string;
publicId: string;
linkedMemoAmount: number; linkedMemoAmount: number;
} }
@ -25,7 +24,6 @@ interface ResourceCreate {
interface ResourcePatch { interface ResourcePatch {
id: ResourceId; id: ResourceId;
filename?: string; filename?: string;
resetPublicId?: boolean;
} }
interface ResourceFind { interface ResourceFind {

View File

@ -3,5 +3,5 @@ export const getResourceUrl = (resource: Resource, withOrigin = true) => {
return resource.externalLink; return resource.externalLink;
} }
return `${withOrigin ? window.location.origin : ""}/o/r/${resource.id}/${resource.publicId}/${encodeURIComponent(resource.filename)}`; return `${withOrigin ? window.location.origin : ""}/o/r/${resource.id}`;
}; };