mirror of
https://github.com/usememos/memos.git
synced 2025-02-14 18:30:42 +01:00
feat: add user-defined id to resource
This commit is contained in:
parent
40bd75c725
commit
582cc6609c
@ -15,6 +15,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/lithammer/shortuuid/v4"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
@ -139,6 +140,7 @@ func (s *APIV1Service) CreateResource(c echo.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
create := &store.Resource{
|
create := &store.Resource{
|
||||||
|
ResourceName: shortuuid.New(),
|
||||||
CreatorID: userID,
|
CreatorID: userID,
|
||||||
Filename: request.Filename,
|
Filename: request.Filename,
|
||||||
ExternalLink: request.ExternalLink,
|
ExternalLink: request.ExternalLink,
|
||||||
@ -215,10 +217,11 @@ func (s *APIV1Service) UploadResource(c echo.Context) error {
|
|||||||
defer sourceFile.Close()
|
defer sourceFile.Close()
|
||||||
|
|
||||||
create := &store.Resource{
|
create := &store.Resource{
|
||||||
CreatorID: userID,
|
ResourceName: shortuuid.New(),
|
||||||
Filename: file.Filename,
|
CreatorID: userID,
|
||||||
Type: file.Header.Get("Content-Type"),
|
Filename: file.Filename,
|
||||||
Size: file.Size,
|
Type: file.Header.Get("Content-Type"),
|
||||||
|
Size: file.Size,
|
||||||
}
|
}
|
||||||
err = SaveResourceBlob(ctx, s.Store, create, sourceFile)
|
err = SaveResourceBlob(ctx, s.Store, create, sourceFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/lithammer/shortuuid/v4"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
"google.golang.org/protobuf/types/known/timestamppb"
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
@ -30,6 +31,7 @@ func (s *APIV2Service) CreateResource(ctx context.Context, request *apiv2pb.Crea
|
|||||||
}
|
}
|
||||||
|
|
||||||
create := &store.Resource{
|
create := &store.Resource{
|
||||||
|
ResourceName: shortuuid.New(),
|
||||||
CreatorID: user.ID,
|
CreatorID: user.ID,
|
||||||
Filename: request.Filename,
|
Filename: request.Filename,
|
||||||
ExternalLink: request.ExternalLink,
|
ExternalLink: request.ExternalLink,
|
||||||
|
@ -86,11 +86,12 @@ func (t *TelegramHandler) MessageHandle(ctx context.Context, bot *telegram.Bot,
|
|||||||
for _, attachment := range attachments {
|
for _, attachment := range attachments {
|
||||||
// Fill the common field of create
|
// Fill the common field of create
|
||||||
create := store.Resource{
|
create := store.Resource{
|
||||||
CreatorID: creatorID,
|
ResourceName: shortuuid.New(),
|
||||||
Filename: filepath.Base(attachment.FileName),
|
CreatorID: creatorID,
|
||||||
Type: attachment.GetMimeType(),
|
Filename: filepath.Base(attachment.FileName),
|
||||||
Size: attachment.FileSize,
|
Type: attachment.GetMimeType(),
|
||||||
MemoID: &memoMessage.ID,
|
Size: attachment.FileSize,
|
||||||
|
MemoID: &memoMessage.ID,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := apiv1.SaveResourceBlob(ctx, t.store, &create, bytes.NewReader(attachment.Data))
|
err := apiv1.SaveResourceBlob(ctx, t.store, &create, bytes.NewReader(attachment.Data))
|
||||||
|
@ -64,6 +64,7 @@ CREATE TABLE `memo_relation` (
|
|||||||
-- resource
|
-- resource
|
||||||
CREATE TABLE `resource` (
|
CREATE TABLE `resource` (
|
||||||
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
`resource_name` VARCHAR(256) NOT NULL UNIQUE,
|
||||||
`creator_id` INT NOT NULL,
|
`creator_id` INT NOT NULL,
|
||||||
`created_ts` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
`created_ts` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
`updated_ts` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
`updated_ts` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
@ -6,15 +6,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
|
|
||||||
"github.com/usememos/memos/store"
|
"github.com/usememos/memos/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (d *DB) CreateResource(ctx context.Context, create *store.Resource) (*store.Resource, error) {
|
func (d *DB) CreateResource(ctx context.Context, create *store.Resource) (*store.Resource, error) {
|
||||||
fields := []string{"`filename`", "`blob`", "`external_link`", "`type`", "`size`", "`creator_id`", "`internal_path`", "`memo_id`"}
|
fields := []string{"`resource_name`", "`filename`", "`blob`", "`external_link`", "`type`", "`size`", "`creator_id`", "`internal_path`", "`memo_id`"}
|
||||||
placeholder := []string{"?", "?", "?", "?", "?", "?", "?", "?"}
|
placeholder := []string{"?", "?", "?", "?", "?", "?", "?", "?", "?"}
|
||||||
args := []any{create.Filename, create.Blob, create.ExternalLink, create.Type, create.Size, create.CreatorID, create.InternalPath, create.MemoID}
|
args := []any{create.ResourceName, create.Filename, create.Blob, create.ExternalLink, create.Type, create.Size, create.CreatorID, create.InternalPath, create.MemoID}
|
||||||
|
|
||||||
stmt := "INSERT INTO `resource` (" + strings.Join(fields, ", ") + ") VALUES (" + strings.Join(placeholder, ", ") + ")"
|
stmt := "INSERT INTO `resource` (" + strings.Join(fields, ", ") + ") VALUES (" + strings.Join(placeholder, ", ") + ")"
|
||||||
result, err := d.db.ExecContext(ctx, stmt, args...)
|
result, err := d.db.ExecContext(ctx, stmt, args...)
|
||||||
@ -28,15 +26,7 @@ func (d *DB) CreateResource(ctx context.Context, create *store.Resource) (*store
|
|||||||
}
|
}
|
||||||
|
|
||||||
id32 := int32(id)
|
id32 := int32(id)
|
||||||
list, err := d.ListResources(ctx, &store.FindResource{ID: &id32})
|
return d.GetResource(ctx, &store.FindResource{ID: &id32})
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(list) != 1 {
|
|
||||||
return nil, errors.Wrapf(nil, "unexpected resource count: %d", len(list))
|
|
||||||
}
|
|
||||||
|
|
||||||
return list[0], nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DB) ListResources(ctx context.Context, find *store.FindResource) ([]*store.Resource, error) {
|
func (d *DB) ListResources(ctx context.Context, find *store.FindResource) ([]*store.Resource, error) {
|
||||||
@ -45,6 +35,9 @@ func (d *DB) ListResources(ctx context.Context, find *store.FindResource) ([]*st
|
|||||||
if v := find.ID; v != nil {
|
if v := find.ID; v != nil {
|
||||||
where, args = append(where, "`id` = ?"), append(args, *v)
|
where, args = append(where, "`id` = ?"), append(args, *v)
|
||||||
}
|
}
|
||||||
|
if v := find.ResourceName; v != nil {
|
||||||
|
where, args = append(where, "`resource_name` = ?"), append(args, *v)
|
||||||
|
}
|
||||||
if v := find.CreatorID; v != nil {
|
if v := find.CreatorID; v != nil {
|
||||||
where, args = append(where, "`creator_id` = ?"), append(args, *v)
|
where, args = append(where, "`creator_id` = ?"), append(args, *v)
|
||||||
}
|
}
|
||||||
@ -58,7 +51,7 @@ func (d *DB) ListResources(ctx context.Context, find *store.FindResource) ([]*st
|
|||||||
where = append(where, "`memo_id` IS NOT NULL")
|
where = append(where, "`memo_id` IS NOT NULL")
|
||||||
}
|
}
|
||||||
|
|
||||||
fields := []string{"`id`", "`filename`", "`external_link`", "`type`", "`size`", "`creator_id`", "UNIX_TIMESTAMP(`created_ts`)", "UNIX_TIMESTAMP(`updated_ts`)", "`internal_path`", "`memo_id`"}
|
fields := []string{"`id`", "`resource_name`", "`filename`", "`external_link`", "`type`", "`size`", "`creator_id`", "UNIX_TIMESTAMP(`created_ts`)", "UNIX_TIMESTAMP(`updated_ts`)", "`internal_path`", "`memo_id`"}
|
||||||
if find.GetBlob {
|
if find.GetBlob {
|
||||||
fields = append(fields, "`blob`")
|
fields = append(fields, "`blob`")
|
||||||
}
|
}
|
||||||
@ -83,6 +76,7 @@ func (d *DB) ListResources(ctx context.Context, find *store.FindResource) ([]*st
|
|||||||
var memoID sql.NullInt32
|
var memoID sql.NullInt32
|
||||||
dests := []any{
|
dests := []any{
|
||||||
&resource.ID,
|
&resource.ID,
|
||||||
|
&resource.ResourceName,
|
||||||
&resource.Filename,
|
&resource.Filename,
|
||||||
&resource.ExternalLink,
|
&resource.ExternalLink,
|
||||||
&resource.Type,
|
&resource.Type,
|
||||||
@ -112,9 +106,24 @@ func (d *DB) ListResources(ctx context.Context, find *store.FindResource) ([]*st
|
|||||||
return list, nil
|
return list, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *DB) GetResource(ctx context.Context, find *store.FindResource) (*store.Resource, error) {
|
||||||
|
list, err := d.ListResources(ctx, find)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(list) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return list[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *DB) UpdateResource(ctx context.Context, update *store.UpdateResource) (*store.Resource, error) {
|
func (d *DB) UpdateResource(ctx context.Context, update *store.UpdateResource) (*store.Resource, error) {
|
||||||
set, args := []string{}, []any{}
|
set, args := []string{}, []any{}
|
||||||
|
|
||||||
|
if v := update.ResourceName; v != nil {
|
||||||
|
set, args = append(set, "`resource_name` = ?"), append(args, *v)
|
||||||
|
}
|
||||||
if v := update.UpdatedTs; v != nil {
|
if v := update.UpdatedTs; v != nil {
|
||||||
set, args = append(set, "`updated_ts` = FROM_UNIXTIME(?)"), append(args, *v)
|
set, args = append(set, "`updated_ts` = FROM_UNIXTIME(?)"), append(args, *v)
|
||||||
}
|
}
|
||||||
@ -137,15 +146,7 @@ func (d *DB) UpdateResource(ctx context.Context, update *store.UpdateResource) (
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
list, err := d.ListResources(ctx, &store.FindResource{ID: &update.ID})
|
return d.GetResource(ctx, &store.FindResource{ID: &update.ID})
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(list) != 1 {
|
|
||||||
return nil, errors.Wrapf(nil, "unexpected resource count: %d", len(list))
|
|
||||||
}
|
|
||||||
|
|
||||||
return list[0], nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DB) DeleteResource(ctx context.Context, delete *store.DeleteResource) error {
|
func (d *DB) DeleteResource(ctx context.Context, delete *store.DeleteResource) error {
|
||||||
|
@ -64,6 +64,7 @@ CREATE TABLE memo_relation (
|
|||||||
-- resource
|
-- resource
|
||||||
CREATE TABLE resource (
|
CREATE TABLE resource (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
|
resource_name TEXT NOT NULL UNIQUE,
|
||||||
creator_id INTEGER NOT NULL,
|
creator_id INTEGER NOT NULL,
|
||||||
created_ts BIGINT NOT NULL DEFAULT EXTRACT(EPOCH FROM NOW()),
|
created_ts BIGINT NOT NULL DEFAULT EXTRACT(EPOCH FROM NOW()),
|
||||||
updated_ts BIGINT NOT NULL DEFAULT EXTRACT(EPOCH FROM NOW()),
|
updated_ts BIGINT NOT NULL DEFAULT EXTRACT(EPOCH FROM NOW()),
|
||||||
|
@ -10,8 +10,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (d *DB) CreateResource(ctx context.Context, create *store.Resource) (*store.Resource, error) {
|
func (d *DB) CreateResource(ctx context.Context, create *store.Resource) (*store.Resource, error) {
|
||||||
fields := []string{"filename", "blob", "external_link", "type", "size", "creator_id", "internal_path", "memo_id"}
|
fields := []string{"resource_name", "filename", "blob", "external_link", "type", "size", "creator_id", "internal_path", "memo_id"}
|
||||||
args := []any{create.Filename, create.Blob, create.ExternalLink, create.Type, create.Size, create.CreatorID, create.InternalPath, create.MemoID}
|
args := []any{create.ResourceName, create.Filename, create.Blob, create.ExternalLink, create.Type, create.Size, create.CreatorID, create.InternalPath, create.MemoID}
|
||||||
|
|
||||||
stmt := "INSERT INTO resource (" + strings.Join(fields, ", ") + ") VALUES (" + placeholders(len(args)) + ") RETURNING id, created_ts, updated_ts"
|
stmt := "INSERT INTO resource (" + strings.Join(fields, ", ") + ") VALUES (" + placeholders(len(args)) + ") RETURNING id, created_ts, updated_ts"
|
||||||
if err := d.db.QueryRowContext(ctx, stmt, args...).Scan(&create.ID, &create.CreatedTs, &create.UpdatedTs); err != nil {
|
if err := d.db.QueryRowContext(ctx, stmt, args...).Scan(&create.ID, &create.CreatedTs, &create.UpdatedTs); err != nil {
|
||||||
@ -26,6 +26,9 @@ func (d *DB) ListResources(ctx context.Context, find *store.FindResource) ([]*st
|
|||||||
if v := find.ID; v != nil {
|
if v := find.ID; v != nil {
|
||||||
where, args = append(where, "id = "+placeholder(len(args)+1)), append(args, *v)
|
where, args = append(where, "id = "+placeholder(len(args)+1)), append(args, *v)
|
||||||
}
|
}
|
||||||
|
if v := find.ResourceName; v != nil {
|
||||||
|
where, args = append(where, "resource_name = "+placeholder(len(args)+1)), append(args, *v)
|
||||||
|
}
|
||||||
if v := find.CreatorID; v != nil {
|
if v := find.CreatorID; v != nil {
|
||||||
where, args = append(where, "creator_id = "+placeholder(len(args)+1)), append(args, *v)
|
where, args = append(where, "creator_id = "+placeholder(len(args)+1)), append(args, *v)
|
||||||
}
|
}
|
||||||
@ -39,7 +42,7 @@ func (d *DB) ListResources(ctx context.Context, find *store.FindResource) ([]*st
|
|||||||
where = append(where, "memo_id IS NOT NULL")
|
where = append(where, "memo_id IS NOT NULL")
|
||||||
}
|
}
|
||||||
|
|
||||||
fields := []string{"id", "filename", "external_link", "type", "size", "creator_id", "created_ts", "updated_ts", "internal_path", "memo_id"}
|
fields := []string{"id", "resource_name", "filename", "external_link", "type", "size", "creator_id", "created_ts", "updated_ts", "internal_path", "memo_id"}
|
||||||
if find.GetBlob {
|
if find.GetBlob {
|
||||||
fields = append(fields, "blob")
|
fields = append(fields, "blob")
|
||||||
}
|
}
|
||||||
@ -70,6 +73,7 @@ func (d *DB) ListResources(ctx context.Context, find *store.FindResource) ([]*st
|
|||||||
var memoID sql.NullInt32
|
var memoID sql.NullInt32
|
||||||
dests := []any{
|
dests := []any{
|
||||||
&resource.ID,
|
&resource.ID,
|
||||||
|
&resource.ResourceName,
|
||||||
&resource.Filename,
|
&resource.Filename,
|
||||||
&resource.ExternalLink,
|
&resource.ExternalLink,
|
||||||
&resource.Type,
|
&resource.Type,
|
||||||
@ -102,6 +106,9 @@ func (d *DB) ListResources(ctx context.Context, find *store.FindResource) ([]*st
|
|||||||
func (d *DB) UpdateResource(ctx context.Context, update *store.UpdateResource) (*store.Resource, error) {
|
func (d *DB) UpdateResource(ctx context.Context, update *store.UpdateResource) (*store.Resource, error) {
|
||||||
set, args := []string{}, []any{}
|
set, args := []string{}, []any{}
|
||||||
|
|
||||||
|
if v := update.ResourceName; v != nil {
|
||||||
|
set, args = append(set, "resource_name = "+placeholder(len(args)+1)), append(args, *v)
|
||||||
|
}
|
||||||
if v := update.UpdatedTs; v != nil {
|
if v := update.UpdatedTs; v != nil {
|
||||||
set, args = append(set, "updated_ts = "+placeholder(len(args)+1)), append(args, *v)
|
set, args = append(set, "updated_ts = "+placeholder(len(args)+1)), append(args, *v)
|
||||||
}
|
}
|
||||||
@ -118,16 +125,13 @@ func (d *DB) UpdateResource(ctx context.Context, update *store.UpdateResource) (
|
|||||||
set, args = append(set, "blob = "+placeholder(len(args)+1)), append(args, v)
|
set, args = append(set, "blob = "+placeholder(len(args)+1)), append(args, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
fields := []string{"id", "filename", "external_link", "type", "size", "creator_id", "created_ts", "updated_ts", "internal_path"}
|
fields := []string{"id", "resource_name", "filename", "external_link", "type", "size", "creator_id", "created_ts", "updated_ts", "internal_path"}
|
||||||
stmt := `
|
stmt := `UPDATE resource SET ` + strings.Join(set, ", ") + ` WHERE id = ` + placeholder(len(args)+1) + ` RETURNING ` + strings.Join(fields, ", ")
|
||||||
UPDATE resource
|
|
||||||
SET ` + strings.Join(set, ", ") + `
|
|
||||||
WHERE id = ` + placeholder(len(args)+1) + `
|
|
||||||
RETURNING ` + strings.Join(fields, ", ")
|
|
||||||
args = append(args, update.ID)
|
args = append(args, update.ID)
|
||||||
resource := store.Resource{}
|
resource := store.Resource{}
|
||||||
dests := []any{
|
dests := []any{
|
||||||
&resource.ID,
|
&resource.ID,
|
||||||
|
&resource.ResourceName,
|
||||||
&resource.Filename,
|
&resource.Filename,
|
||||||
&resource.ExternalLink,
|
&resource.ExternalLink,
|
||||||
&resource.Type,
|
&resource.Type,
|
||||||
@ -157,11 +161,7 @@ func (d *DB) DeleteResource(ctx context.Context, delete *store.DeleteResource) e
|
|||||||
}
|
}
|
||||||
|
|
||||||
func vacuumResource(ctx context.Context, tx *sql.Tx) error {
|
func vacuumResource(ctx context.Context, tx *sql.Tx) error {
|
||||||
stmt := `
|
stmt := `DELETE FROM resource WHERE creator_id NOT IN (SELECT id FROM "user")`
|
||||||
DELETE FROM
|
|
||||||
resource
|
|
||||||
WHERE
|
|
||||||
creator_id NOT IN (SELECT id FROM "user")`
|
|
||||||
_, err := tx.ExecContext(ctx, stmt)
|
_, err := tx.ExecContext(ctx, stmt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1,19 +1,3 @@
|
|||||||
-- drop all tables first
|
|
||||||
DROP TABLE IF EXISTS migration_history;
|
|
||||||
DROP TABLE IF EXISTS system_setting;
|
|
||||||
DROP TABLE IF EXISTS user;
|
|
||||||
DROP TABLE IF EXISTS user_setting;
|
|
||||||
DROP TABLE IF EXISTS memo;
|
|
||||||
DROP TABLE IF EXISTS memo_organizer;
|
|
||||||
DROP TABLE IF EXISTS memo_relation;
|
|
||||||
DROP TABLE IF EXISTS resource;
|
|
||||||
DROP TABLE IF EXISTS tag;
|
|
||||||
DROP TABLE IF EXISTS activity;
|
|
||||||
DROP TABLE IF EXISTS storage;
|
|
||||||
DROP TABLE IF EXISTS idp;
|
|
||||||
DROP TABLE IF EXISTS inbox;
|
|
||||||
DROP TABLE IF EXISTS webhook;
|
|
||||||
|
|
||||||
-- migration_history
|
-- migration_history
|
||||||
CREATE TABLE migration_history (
|
CREATE TABLE migration_history (
|
||||||
version TEXT NOT NULL PRIMARY KEY,
|
version TEXT NOT NULL PRIMARY KEY,
|
||||||
@ -87,6 +71,7 @@ CREATE TABLE memo_relation (
|
|||||||
-- resource
|
-- resource
|
||||||
CREATE TABLE resource (
|
CREATE TABLE resource (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
resource_name TEXT NOT NULL UNIQUE,
|
||||||
creator_id INTEGER NOT NULL,
|
creator_id INTEGER NOT NULL,
|
||||||
created_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
|
created_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
|
||||||
updated_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
|
updated_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
|
||||||
|
@ -10,9 +10,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (d *DB) CreateResource(ctx context.Context, create *store.Resource) (*store.Resource, error) {
|
func (d *DB) CreateResource(ctx context.Context, create *store.Resource) (*store.Resource, error) {
|
||||||
fields := []string{"`filename`", "`blob`", "`external_link`", "`type`", "`size`", "`creator_id`", "`internal_path`", "`memo_id`"}
|
fields := []string{"`resource_name`", "`filename`", "`blob`", "`external_link`", "`type`", "`size`", "`creator_id`", "`internal_path`", "`memo_id`"}
|
||||||
placeholder := []string{"?", "?", "?", "?", "?", "?", "?", "?"}
|
placeholder := []string{"?", "?", "?", "?", "?", "?", "?", "?", "?"}
|
||||||
args := []any{create.Filename, create.Blob, create.ExternalLink, create.Type, create.Size, create.CreatorID, create.InternalPath, create.MemoID}
|
args := []any{create.ResourceName, create.Filename, create.Blob, create.ExternalLink, create.Type, create.Size, create.CreatorID, create.InternalPath, create.MemoID}
|
||||||
|
|
||||||
stmt := "INSERT INTO `resource` (" + strings.Join(fields, ", ") + ") VALUES (" + strings.Join(placeholder, ", ") + ") RETURNING `id`, `created_ts`, `updated_ts`"
|
stmt := "INSERT INTO `resource` (" + strings.Join(fields, ", ") + ") VALUES (" + strings.Join(placeholder, ", ") + ") RETURNING `id`, `created_ts`, `updated_ts`"
|
||||||
if err := d.db.QueryRowContext(ctx, stmt, args...).Scan(&create.ID, &create.CreatedTs, &create.UpdatedTs); err != nil {
|
if err := d.db.QueryRowContext(ctx, stmt, args...).Scan(&create.ID, &create.CreatedTs, &create.UpdatedTs); err != nil {
|
||||||
@ -26,33 +26,30 @@ func (d *DB) ListResources(ctx context.Context, find *store.FindResource) ([]*st
|
|||||||
where, args := []string{"1 = 1"}, []any{}
|
where, args := []string{"1 = 1"}, []any{}
|
||||||
|
|
||||||
if v := find.ID; v != nil {
|
if v := find.ID; v != nil {
|
||||||
where, args = append(where, "id = ?"), append(args, *v)
|
where, args = append(where, "`id` = ?"), append(args, *v)
|
||||||
|
}
|
||||||
|
if v := find.ResourceName; v != nil {
|
||||||
|
where, args = append(where, "`resource_name` = ?"), append(args, *v)
|
||||||
}
|
}
|
||||||
if v := find.CreatorID; v != nil {
|
if v := find.CreatorID; v != nil {
|
||||||
where, args = append(where, "creator_id = ?"), append(args, *v)
|
where, args = append(where, "`creator_id` = ?"), append(args, *v)
|
||||||
}
|
}
|
||||||
if v := find.Filename; v != nil {
|
if v := find.Filename; v != nil {
|
||||||
where, args = append(where, "filename = ?"), append(args, *v)
|
where, args = append(where, "`filename` = ?"), append(args, *v)
|
||||||
}
|
}
|
||||||
if v := find.MemoID; v != nil {
|
if v := find.MemoID; v != nil {
|
||||||
where, args = append(where, "memo_id = ?"), append(args, *v)
|
where, args = append(where, "`memo_id` = ?"), append(args, *v)
|
||||||
}
|
}
|
||||||
if find.HasRelatedMemo {
|
if find.HasRelatedMemo {
|
||||||
where = append(where, "memo_id IS NOT NULL")
|
where = append(where, "`memo_id` IS NOT NULL")
|
||||||
}
|
}
|
||||||
|
|
||||||
fields := []string{"id", "filename", "external_link", "type", "size", "creator_id", "created_ts", "updated_ts", "internal_path", "memo_id"}
|
fields := []string{"`id`", "`resource_name`", "`filename`", "`external_link`", "`type`", "`size`", "`creator_id`", "`created_ts`", "`updated_ts`", "`internal_path`", "`memo_id`"}
|
||||||
if find.GetBlob {
|
if find.GetBlob {
|
||||||
fields = append(fields, "blob")
|
fields = append(fields, "`blob`")
|
||||||
}
|
}
|
||||||
|
|
||||||
query := fmt.Sprintf(`
|
query := fmt.Sprintf("SELECT %s FROM `resource` WHERE %s ORDER BY `updated_ts` DESC, `created_ts` DESC", strings.Join(fields, ", "), strings.Join(where, " AND "))
|
||||||
SELECT
|
|
||||||
%s
|
|
||||||
FROM resource
|
|
||||||
WHERE %s
|
|
||||||
ORDER BY updated_ts DESC, created_ts DESC
|
|
||||||
`, strings.Join(fields, ", "), strings.Join(where, " AND "))
|
|
||||||
if find.Limit != nil {
|
if find.Limit != nil {
|
||||||
query = fmt.Sprintf("%s LIMIT %d", query, *find.Limit)
|
query = fmt.Sprintf("%s LIMIT %d", query, *find.Limit)
|
||||||
if find.Offset != nil {
|
if find.Offset != nil {
|
||||||
@ -72,6 +69,7 @@ func (d *DB) ListResources(ctx context.Context, find *store.FindResource) ([]*st
|
|||||||
var memoID sql.NullInt32
|
var memoID sql.NullInt32
|
||||||
dests := []any{
|
dests := []any{
|
||||||
&resource.ID,
|
&resource.ID,
|
||||||
|
&resource.ResourceName,
|
||||||
&resource.Filename,
|
&resource.Filename,
|
||||||
&resource.ExternalLink,
|
&resource.ExternalLink,
|
||||||
&resource.Type,
|
&resource.Type,
|
||||||
@ -104,32 +102,32 @@ func (d *DB) ListResources(ctx context.Context, find *store.FindResource) ([]*st
|
|||||||
func (d *DB) UpdateResource(ctx context.Context, update *store.UpdateResource) (*store.Resource, error) {
|
func (d *DB) UpdateResource(ctx context.Context, update *store.UpdateResource) (*store.Resource, error) {
|
||||||
set, args := []string{}, []any{}
|
set, args := []string{}, []any{}
|
||||||
|
|
||||||
|
if v := update.ResourceName; v != nil {
|
||||||
|
set, args = append(set, "`resource_name` = ?"), append(args, *v)
|
||||||
|
}
|
||||||
if v := update.UpdatedTs; v != nil {
|
if v := update.UpdatedTs; v != nil {
|
||||||
set, args = append(set, "updated_ts = ?"), append(args, *v)
|
set, args = append(set, "`updated_ts` = ?"), append(args, *v)
|
||||||
}
|
}
|
||||||
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.InternalPath; v != nil {
|
if v := update.InternalPath; v != nil {
|
||||||
set, args = append(set, "internal_path = ?"), append(args, *v)
|
set, args = append(set, "`internal_path` = ?"), append(args, *v)
|
||||||
}
|
}
|
||||||
if v := update.MemoID; v != nil {
|
if v := update.MemoID; v != nil {
|
||||||
set, args = append(set, "memo_id = ?"), append(args, *v)
|
set, args = append(set, "`memo_id` = ?"), append(args, *v)
|
||||||
}
|
}
|
||||||
if v := update.Blob; v != nil {
|
if v := update.Blob; v != nil {
|
||||||
set, args = append(set, "blob = ?"), append(args, v)
|
set, args = append(set, "`blob` = ?"), 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"}
|
fields := []string{"`id`", "`resource_name`", "`filename`", "`external_link`", "`type`", "`size`", "`creator_id`", "`created_ts`", "`updated_ts`", "`internal_path`"}
|
||||||
stmt := `
|
stmt := "UPDATE `resource` SET " + strings.Join(set, ", ") + " WHERE `id` = ? RETURNING " + strings.Join(fields, ", ")
|
||||||
UPDATE resource
|
|
||||||
SET ` + strings.Join(set, ", ") + `
|
|
||||||
WHERE id = ?
|
|
||||||
RETURNING ` + strings.Join(fields, ", ")
|
|
||||||
resource := store.Resource{}
|
resource := store.Resource{}
|
||||||
dests := []any{
|
dests := []any{
|
||||||
&resource.ID,
|
&resource.ID,
|
||||||
|
&resource.ResourceName,
|
||||||
&resource.Filename,
|
&resource.Filename,
|
||||||
&resource.ExternalLink,
|
&resource.ExternalLink,
|
||||||
&resource.Type,
|
&resource.Type,
|
||||||
@ -147,10 +145,7 @@ func (d *DB) UpdateResource(ctx context.Context, update *store.UpdateResource) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *DB) DeleteResource(ctx context.Context, delete *store.DeleteResource) error {
|
func (d *DB) DeleteResource(ctx context.Context, delete *store.DeleteResource) error {
|
||||||
stmt := `
|
stmt := "DELETE FROM `resource` WHERE `id` = ?"
|
||||||
DELETE FROM resource
|
|
||||||
WHERE id = ?
|
|
||||||
`
|
|
||||||
result, err := d.db.ExecContext(ctx, stmt, delete.ID)
|
result, err := d.db.ExecContext(ctx, stmt, delete.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -168,16 +163,7 @@ func (d *DB) DeleteResource(ctx context.Context, delete *store.DeleteResource) e
|
|||||||
}
|
}
|
||||||
|
|
||||||
func vacuumResource(ctx context.Context, tx *sql.Tx) error {
|
func vacuumResource(ctx context.Context, tx *sql.Tx) error {
|
||||||
stmt := `
|
stmt := "DELETE FROM `resource` WHERE `creator_id` NOT IN (SELECT `id` FROM `user`)"
|
||||||
DELETE FROM
|
|
||||||
resource
|
|
||||||
WHERE
|
|
||||||
creator_id NOT IN (
|
|
||||||
SELECT
|
|
||||||
id
|
|
||||||
FROM
|
|
||||||
user
|
|
||||||
)`
|
|
||||||
_, err := tx.ExecContext(ctx, stmt)
|
_, err := tx.ExecContext(ctx, stmt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -17,7 +17,8 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Resource struct {
|
type Resource struct {
|
||||||
ID int32
|
ID int32
|
||||||
|
ResourceName string
|
||||||
|
|
||||||
// Standard fields
|
// Standard fields
|
||||||
CreatorID int32
|
CreatorID int32
|
||||||
@ -37,6 +38,7 @@ type Resource struct {
|
|||||||
type FindResource struct {
|
type FindResource struct {
|
||||||
GetBlob bool
|
GetBlob bool
|
||||||
ID *int32
|
ID *int32
|
||||||
|
ResourceName *string
|
||||||
CreatorID *int32
|
CreatorID *int32
|
||||||
Filename *string
|
Filename *string
|
||||||
MemoID *int32
|
MemoID *int32
|
||||||
@ -47,6 +49,7 @@ type FindResource struct {
|
|||||||
|
|
||||||
type UpdateResource struct {
|
type UpdateResource struct {
|
||||||
ID int32
|
ID int32
|
||||||
|
ResourceName *string
|
||||||
UpdatedTs *int64
|
UpdatedTs *int64
|
||||||
Filename *string
|
Filename *string
|
||||||
InternalPath *string
|
InternalPath *string
|
||||||
@ -60,6 +63,9 @@ type DeleteResource struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) CreateResource(ctx context.Context, create *Resource) (*Resource, error) {
|
func (s *Store) CreateResource(ctx context.Context, create *Resource) (*Resource, error) {
|
||||||
|
if !util.ResourceNameMatcher.MatchString(create.ResourceName) {
|
||||||
|
return nil, errors.New("invalid resource name")
|
||||||
|
}
|
||||||
return s.driver.CreateResource(ctx, create)
|
return s.driver.CreateResource(ctx, create)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,6 +87,9 @@ func (s *Store) GetResource(ctx context.Context, find *FindResource) (*Resource,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) UpdateResource(ctx context.Context, update *UpdateResource) (*Resource, error) {
|
func (s *Store) UpdateResource(ctx context.Context, update *UpdateResource) (*Resource, error) {
|
||||||
|
if update.ResourceName != nil && !util.ResourceNameMatcher.MatchString(*update.ResourceName) {
|
||||||
|
return nil, errors.New("invalid resource name")
|
||||||
|
}
|
||||||
return s.driver.UpdateResource(ctx, update)
|
return s.driver.UpdateResource(ctx, update)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,6 +110,7 @@ func (s *Store) DeleteResource(ctx context.Context, delete *DeleteResource) erro
|
|||||||
}
|
}
|
||||||
_ = os.Remove(resourcePath)
|
_ = os.Remove(resourcePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the thumbnail.
|
// Delete the thumbnail.
|
||||||
if util.HasPrefixes(resource.Type, "image/png", "image/jpeg") {
|
if util.HasPrefixes(resource.Type, "image/png", "image/jpeg") {
|
||||||
ext := filepath.Ext(resource.Filename)
|
ext := filepath.Ext(resource.Filename)
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/lithammer/shortuuid/v4"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/usememos/memos/store"
|
"github.com/usememos/memos/store"
|
||||||
@ -33,6 +34,7 @@ func TestMigrateResourceInternalPath(t *testing.T) {
|
|||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
for input, expectedOutput := range testCase {
|
for input, expectedOutput := range testCase {
|
||||||
resourceCreate := &store.Resource{
|
resourceCreate := &store.Resource{
|
||||||
|
ResourceName: shortuuid.New(),
|
||||||
CreatorID: user.ID,
|
CreatorID: user.ID,
|
||||||
InternalPath: input,
|
InternalPath: input,
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/lithammer/shortuuid/v4"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/usememos/memos/store"
|
"github.com/usememos/memos/store"
|
||||||
@ -13,6 +14,7 @@ func TestResourceStore(t *testing.T) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
ts := NewTestingStore(ctx, t)
|
ts := NewTestingStore(ctx, t)
|
||||||
_, err := ts.CreateResource(ctx, &store.Resource{
|
_, err := ts.CreateResource(ctx, &store.Resource{
|
||||||
|
ResourceName: shortuuid.New(),
|
||||||
CreatorID: 101,
|
CreatorID: 101,
|
||||||
Filename: "test.epub",
|
Filename: "test.epub",
|
||||||
Blob: []byte("test"),
|
Blob: []byte("test"),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user