Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
canifa_note
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Vũ Hoàng Anh
canifa_note
Commits
1fa9f162
Unverified
Commit
1fa9f162
authored
Jul 05, 2023
by
boojack
Committed by
GitHub
Jul 05, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactor: migrate resource to apiv1 (#1901)
parent
5ea561af
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
419 additions
and
339 deletions
+419
-339
resource.go
api/resource.go
+0
-48
memo_resource.go
api/v1/memo_resource.go
+24
-0
resource.go
api/v1/resource.go
+137
-75
v1.go
api/v1/v1.go
+7
-0
memo.go
server/memo.go
+21
-2
memo_resource.go
server/memo_resource.go
+9
-7
rss.go
server/rss.go
+1
-2
server.go
server/server.go
+0
-2
telegram.go
server/telegram.go
+2
-3
memo_resource.go
store/memo_resource.go
+79
-0
resource.go
store/resource.go
+110
-172
store.go
store/store.go
+0
-1
resource_test.go
test/store/resource_test.go
+14
-12
api.ts
web/src/helpers/api.ts
+9
-9
resource.ts
web/src/store/module/resource.ts
+6
-6
No files found.
api/resource.go
View file @
1fa9f162
...
@@ -20,51 +20,3 @@ type Resource struct {
...
@@ -20,51 +20,3 @@ type Resource struct {
// Related fields
// Related fields
LinkedMemoAmount
int
`json:"linkedMemoAmount"`
LinkedMemoAmount
int
`json:"linkedMemoAmount"`
}
}
type
ResourceCreate
struct
{
// Standard fields
CreatorID
int
`json:"-"`
// Domain specific fields
Filename
string
`json:"filename"`
Blob
[]
byte
`json:"-"`
InternalPath
string
`json:"internalPath"`
ExternalLink
string
`json:"externalLink"`
Type
string
`json:"type"`
Size
int64
`json:"-"`
PublicID
string
`json:"publicId"`
DownloadToLocal
bool
`json:"downloadToLocal"`
}
type
ResourceFind
struct
{
ID
*
int
`json:"id"`
// Standard fields
CreatorID
*
int
`json:"creatorId"`
// Domain specific fields
Filename
*
string
`json:"filename"`
MemoID
*
int
PublicID
*
string
`json:"publicId"`
GetBlob
bool
// Pagination
Limit
*
int
Offset
*
int
}
type
ResourcePatch
struct
{
ID
int
`json:"-"`
// Standard fields
UpdatedTs
*
int64
// Domain specific fields
Filename
*
string
`json:"filename"`
ResetPublicID
*
bool
`json:"resetPublicId"`
PublicID
*
string
`json:"-"`
}
type
ResourceDelete
struct
{
ID
int
}
api/v1/memo_resource.go
0 → 100644
View file @
1fa9f162
package
v1
type
MemoResource
struct
{
MemoID
int
ResourceID
int
CreatedTs
int64
UpdatedTs
int64
}
type
MemoResourceUpsert
struct
{
MemoID
int
`json:"-"`
ResourceID
int
UpdatedTs
*
int64
}
type
MemoResourceFind
struct
{
MemoID
*
int
ResourceID
*
int
}
type
MemoResourceDelete
struct
{
MemoID
*
int
ResourceID
*
int
}
server
/resource.go
→
api/v1
/resource.go
View file @
1fa9f162
package
server
package
v1
import
(
import
(
"bytes"
"bytes"
...
@@ -21,8 +21,6 @@ import (
...
@@ -21,8 +21,6 @@ import (
"github.com/disintegration/imaging"
"github.com/disintegration/imaging"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4"
"github.com/pkg/errors"
"github.com/pkg/errors"
"github.com/usememos/memos/api"
apiv1
"github.com/usememos/memos/api/v1"
"github.com/usememos/memos/common"
"github.com/usememos/memos/common"
"github.com/usememos/memos/common/log"
"github.com/usememos/memos/common/log"
"github.com/usememos/memos/plugin/storage/s3"
"github.com/usememos/memos/plugin/storage/s3"
...
@@ -30,6 +28,48 @@ import (
...
@@ -30,6 +28,48 @@ import (
"go.uber.org/zap"
"go.uber.org/zap"
)
)
type
Resource
struct
{
ID
int
`json:"id"`
// Standard fields
CreatorID
int
`json:"creatorId"`
CreatedTs
int64
`json:"createdTs"`
UpdatedTs
int64
`json:"updatedTs"`
// Domain specific fields
Filename
string
`json:"filename"`
Blob
[]
byte
`json:"-"`
InternalPath
string
`json:"-"`
ExternalLink
string
`json:"externalLink"`
Type
string
`json:"type"`
Size
int64
`json:"size"`
PublicID
string
`json:"publicId"`
// Related fields
LinkedMemoAmount
int
`json:"linkedMemoAmount"`
}
type
CreateResourceRequest
struct
{
Filename
string
`json:"filename"`
InternalPath
string
`json:"internalPath"`
ExternalLink
string
`json:"externalLink"`
Type
string
`json:"type"`
PublicID
string
`json:"publicId"`
DownloadToLocal
bool
`json:"downloadToLocal"`
}
type
FindResourceRequest
struct
{
ID
*
int
`json:"id"`
CreatorID
*
int
`json:"creatorId"`
Filename
*
string
`json:"filename"`
PublicID
*
string
`json:"publicId"`
}
type
UpdateResourceRequest
struct
{
Filename
*
string
`json:"filename"`
ResetPublicID
*
bool
`json:"resetPublicId"`
}
const
(
const
(
// The upload memory buffer is 32 MiB.
// The upload memory buffer is 32 MiB.
// It should be kept low, so RAM usage doesn't get out of control.
// It should be kept low, so RAM usage doesn't get out of control.
...
@@ -43,7 +83,7 @@ const (
...
@@ -43,7 +83,7 @@ const (
var
fileKeyPattern
=
regexp
.
MustCompile
(
`\{[a-z]{1,9}\}`
)
var
fileKeyPattern
=
regexp
.
MustCompile
(
`\{[a-z]{1,9}\}`
)
func
(
s
*
Server
)
registerResourceRoutes
(
g
*
echo
.
Group
)
{
func
(
s
*
APIV1Service
)
registerResourceRoutes
(
g
*
echo
.
Group
)
{
g
.
POST
(
"/resource"
,
func
(
c
echo
.
Context
)
error
{
g
.
POST
(
"/resource"
,
func
(
c
echo
.
Context
)
error
{
ctx
:=
c
.
Request
()
.
Context
()
ctx
:=
c
.
Request
()
.
Context
()
userID
,
ok
:=
c
.
Get
(
getUserIDContextKey
())
.
(
int
)
userID
,
ok
:=
c
.
Get
(
getUserIDContextKey
())
.
(
int
)
...
@@ -51,15 +91,21 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
...
@@ -51,15 +91,21 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
return
echo
.
NewHTTPError
(
http
.
StatusUnauthorized
,
"Missing user in session"
)
return
echo
.
NewHTTPError
(
http
.
StatusUnauthorized
,
"Missing user in session"
)
}
}
re
sourceCreate
:=
&
api
.
ResourceCreate
{}
re
quest
:=
&
CreateResourceRequest
{}
if
err
:=
json
.
NewDecoder
(
c
.
Request
()
.
Body
)
.
Decode
(
re
sourceCreate
);
err
!=
nil
{
if
err
:=
json
.
NewDecoder
(
c
.
Request
()
.
Body
)
.
Decode
(
re
quest
);
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusBadRequest
,
"Malformatted post resource request"
)
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusBadRequest
,
"Malformatted post resource request"
)
.
SetInternal
(
err
)
}
}
resourceCreate
.
CreatorID
=
userID
create
:=
&
store
.
Resource
{
if
resourceCreate
.
ExternalLink
!=
""
{
CreatorID
:
userID
,
Filename
:
request
.
Filename
,
ExternalLink
:
request
.
ExternalLink
,
Type
:
request
.
Type
,
PublicID
:
common
.
GenUUID
(),
}
if
request
.
ExternalLink
!=
""
{
// Only allow those external links scheme with http/https
// Only allow those external links scheme with http/https
linkURL
,
err
:=
url
.
Parse
(
re
sourceCreate
.
ExternalLink
)
linkURL
,
err
:=
url
.
Parse
(
re
quest
.
ExternalLink
)
if
err
!=
nil
{
if
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusBadRequest
,
"Invalid external link"
)
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusBadRequest
,
"Invalid external link"
)
.
SetInternal
(
err
)
}
}
...
@@ -67,24 +113,24 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
...
@@ -67,24 +113,24 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
return
echo
.
NewHTTPError
(
http
.
StatusBadRequest
,
"Invalid external link scheme"
)
return
echo
.
NewHTTPError
(
http
.
StatusBadRequest
,
"Invalid external link scheme"
)
}
}
if
re
sourceCreate
.
DownloadToLocal
{
if
re
quest
.
DownloadToLocal
{
resp
,
err
:=
http
.
Get
(
linkURL
.
String
())
resp
,
err
:=
http
.
Get
(
linkURL
.
String
())
if
err
!=
nil
{
if
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusBadRequest
,
"Failed to request "
+
resourceCreate
.
ExternalLink
)
return
echo
.
NewHTTPError
(
http
.
StatusBadRequest
,
fmt
.
Sprintf
(
"Failed to request %s"
,
request
.
ExternalLink
)
)
}
}
defer
resp
.
Body
.
Close
()
defer
resp
.
Body
.
Close
()
blob
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
blob
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
if
err
!=
nil
{
if
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusBadRequest
,
"Failed to read "
+
resourceCreate
.
ExternalLink
)
return
echo
.
NewHTTPError
(
http
.
StatusBadRequest
,
fmt
.
Sprintf
(
"Failed to read %s"
,
request
.
ExternalLink
)
)
}
}
resourceC
reate
.
Blob
=
blob
c
reate
.
Blob
=
blob
mediaType
,
_
,
err
:=
mime
.
ParseMediaType
(
resp
.
Header
.
Get
(
"Content-Type"
))
mediaType
,
_
,
err
:=
mime
.
ParseMediaType
(
resp
.
Header
.
Get
(
"Content-Type"
))
if
err
!=
nil
{
if
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusBadRequest
,
"Failed to read mime from "
+
resourceCreate
.
ExternalLink
)
return
echo
.
NewHTTPError
(
http
.
StatusBadRequest
,
fmt
.
Sprintf
(
"Failed to read mime from %s"
,
request
.
ExternalLink
)
)
}
}
resourceC
reate
.
Type
=
mediaType
c
reate
.
Type
=
mediaType
filename
:=
path
.
Base
(
linkURL
.
Path
)
filename
:=
path
.
Base
(
linkURL
.
Path
)
if
path
.
Ext
(
filename
)
==
""
{
if
path
.
Ext
(
filename
)
==
""
{
...
@@ -93,20 +139,19 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
...
@@ -93,20 +139,19 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
filename
+=
extensions
[
0
]
filename
+=
extensions
[
0
]
}
}
}
}
resourceCreate
.
Filename
=
filename
create
.
Filename
=
filename
resourceCreate
.
PublicID
=
common
.
GenUUID
()
create
.
ExternalLink
=
""
resourceCreate
.
ExternalLink
=
""
}
}
}
}
resource
,
err
:=
s
.
Store
.
CreateResource
(
ctx
,
resourceC
reate
)
resource
,
err
:=
s
.
Store
.
CreateResource
V1
(
ctx
,
c
reate
)
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
)
}
}
if
err
:=
s
.
createResourceCreateActivity
(
ctx
,
resource
);
err
!=
nil
{
if
err
:=
s
.
createResourceCreateActivity
(
ctx
,
resource
);
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to create activity"
)
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to create activity"
)
.
SetInternal
(
err
)
}
}
return
c
.
JSON
(
http
.
StatusOK
,
co
mposeRespons
e
(
resource
))
return
c
.
JSON
(
http
.
StatusOK
,
co
nvertResourceFromStor
e
(
resource
))
})
})
g
.
POST
(
"/resource/blob"
,
func
(
c
echo
.
Context
)
error
{
g
.
POST
(
"/resource/blob"
,
func
(
c
echo
.
Context
)
error
{
...
@@ -117,7 +162,7 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
...
@@ -117,7 +162,7 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
}
}
// This is the backend default max upload size limit.
// This is the backend default max upload size limit.
maxUploadSetting
:=
s
.
Store
.
GetSystemSettingValueWithDefault
(
&
ctx
,
apiv1
.
SystemSettingMaxUploadSizeMiBName
.
String
(),
"32"
)
maxUploadSetting
:=
s
.
Store
.
GetSystemSettingValueWithDefault
(
&
ctx
,
SystemSettingMaxUploadSizeMiBName
.
String
(),
"32"
)
var
settingMaxUploadSizeBytes
int
var
settingMaxUploadSizeBytes
int
if
settingMaxUploadSizeMiB
,
err
:=
strconv
.
Atoi
(
maxUploadSetting
);
err
==
nil
{
if
settingMaxUploadSizeMiB
,
err
:=
strconv
.
Atoi
(
maxUploadSetting
);
err
==
nil
{
settingMaxUploadSizeBytes
=
settingMaxUploadSizeMiB
*
MebiByte
settingMaxUploadSizeBytes
=
settingMaxUploadSizeMiB
*
MebiByte
...
@@ -150,12 +195,12 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
...
@@ -150,12 +195,12 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
}
}
defer
sourceFile
.
Close
()
defer
sourceFile
.
Close
()
var
resourceCreate
*
api
.
ResourceCreate
create
:=
&
store
.
Resource
{}
systemSettingStorageServiceID
,
err
:=
s
.
Store
.
GetSystemSetting
(
ctx
,
&
store
.
FindSystemSetting
{
Name
:
apiv1
.
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
)
}
}
storageServiceID
:=
apiv1
.
DatabaseStorage
storageServiceID
:=
DatabaseStorage
if
systemSettingStorageServiceID
!=
nil
{
if
systemSettingStorageServiceID
!=
nil
{
err
=
json
.
Unmarshal
([]
byte
(
systemSettingStorageServiceID
.
Value
),
&
storageServiceID
)
err
=
json
.
Unmarshal
([]
byte
(
systemSettingStorageServiceID
.
Value
),
&
storageServiceID
)
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -164,23 +209,23 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
...
@@ -164,23 +209,23 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
}
}
publicID
:=
common
.
GenUUID
()
publicID
:=
common
.
GenUUID
()
if
storageServiceID
==
apiv1
.
DatabaseStorage
{
if
storageServiceID
==
DatabaseStorage
{
fileBytes
,
err
:=
io
.
ReadAll
(
sourceFile
)
fileBytes
,
err
:=
io
.
ReadAll
(
sourceFile
)
if
err
!=
nil
{
if
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to read file"
)
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to read file"
)
.
SetInternal
(
err
)
}
}
resourceCreate
=
&
api
.
ResourceCreat
e
{
create
=
&
store
.
Resourc
e
{
CreatorID
:
userID
,
CreatorID
:
userID
,
Filename
:
file
.
Filename
,
Filename
:
file
.
Filename
,
Type
:
filetype
,
Type
:
filetype
,
Size
:
size
,
Size
:
size
,
Blob
:
fileBytes
,
Blob
:
fileBytes
,
}
}
}
else
if
storageServiceID
==
apiv1
.
LocalStorage
{
}
else
if
storageServiceID
==
LocalStorage
{
// filepath.Join() should be used for local file paths,
// filepath.Join() should be used for local file paths,
// as it handles the os-specific path separator automatically.
// as it handles the os-specific path separator automatically.
// path.Join() always uses '/' as path separator.
// path.Join() always uses '/' as path separator.
systemSettingLocalStoragePath
,
err
:=
s
.
Store
.
GetSystemSetting
(
ctx
,
&
store
.
FindSystemSetting
{
Name
:
apiv1
.
SystemSettingLocalStoragePathName
.
String
()})
systemSettingLocalStoragePath
,
err
:=
s
.
Store
.
GetSystemSetting
(
ctx
,
&
store
.
FindSystemSetting
{
Name
:
SystemSettingLocalStoragePathName
.
String
()})
if
err
!=
nil
&&
common
.
ErrorCode
(
err
)
!=
common
.
NotFound
{
if
err
!=
nil
&&
common
.
ErrorCode
(
err
)
!=
common
.
NotFound
{
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
)
}
}
...
@@ -211,7 +256,7 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
...
@@ -211,7 +256,7 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to copy file"
)
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to copy file"
)
.
SetInternal
(
err
)
}
}
resourceCreate
=
&
api
.
ResourceCreat
e
{
create
=
&
store
.
Resourc
e
{
CreatorID
:
userID
,
CreatorID
:
userID
,
Filename
:
file
.
Filename
,
Filename
:
file
.
Filename
,
Type
:
filetype
,
Type
:
filetype
,
...
@@ -223,12 +268,12 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
...
@@ -223,12 +268,12 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
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
)
}
}
storageMessage
,
err
:=
apiv1
.
ConvertStorageFromStore
(
storage
)
storageMessage
,
err
:=
ConvertStorageFromStore
(
storage
)
if
err
!=
nil
{
if
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to convert storage"
)
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to convert storage"
)
.
SetInternal
(
err
)
}
}
if
storageMessage
.
Type
==
apiv1
.
StorageS3
{
if
storageMessage
.
Type
==
StorageS3
{
s3Config
:=
storageMessage
.
Config
.
S3Config
s3Config
:=
storageMessage
.
Config
.
S3Config
s3Client
,
err
:=
s3
.
NewClient
(
ctx
,
&
s3
.
Config
{
s3Client
,
err
:=
s3
.
NewClient
(
ctx
,
&
s3
.
Config
{
AccessKey
:
s3Config
.
AccessKey
,
AccessKey
:
s3Config
.
AccessKey
,
...
@@ -253,7 +298,7 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
...
@@ -253,7 +298,7 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
if
err
!=
nil
{
if
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to upload via s3 client"
)
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to upload via s3 client"
)
.
SetInternal
(
err
)
}
}
resourceCreate
=
&
api
.
ResourceCreat
e
{
create
=
&
store
.
Resourc
e
{
CreatorID
:
userID
,
CreatorID
:
userID
,
Filename
:
filename
,
Filename
:
filename
,
Type
:
filetype
,
Type
:
filetype
,
...
@@ -265,15 +310,15 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
...
@@ -265,15 +310,15 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
}
}
}
}
resourceC
reate
.
PublicID
=
publicID
c
reate
.
PublicID
=
publicID
resource
,
err
:=
s
.
Store
.
CreateResource
(
ctx
,
resourceC
reate
)
resource
,
err
:=
s
.
Store
.
CreateResource
V1
(
ctx
,
c
reate
)
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
)
}
}
if
err
:=
s
.
createResourceCreateActivity
(
ctx
,
resource
);
err
!=
nil
{
if
err
:=
s
.
createResourceCreateActivity
(
ctx
,
resource
);
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to create activity"
)
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to create activity"
)
.
SetInternal
(
err
)
}
}
return
c
.
JSON
(
http
.
StatusOK
,
co
mposeRespons
e
(
resource
))
return
c
.
JSON
(
http
.
StatusOK
,
co
nvertResourceFromStor
e
(
resource
))
})
})
g
.
GET
(
"/resource"
,
func
(
c
echo
.
Context
)
error
{
g
.
GET
(
"/resource"
,
func
(
c
echo
.
Context
)
error
{
...
@@ -282,21 +327,25 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
...
@@ -282,21 +327,25 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
if
!
ok
{
if
!
ok
{
return
echo
.
NewHTTPError
(
http
.
StatusUnauthorized
,
"Missing user in session"
)
return
echo
.
NewHTTPError
(
http
.
StatusUnauthorized
,
"Missing user in session"
)
}
}
resourceFind
:=
&
api
.
ResourceFind
{
find
:=
&
store
.
FindResource
{
CreatorID
:
&
userID
,
CreatorID
:
&
userID
,
}
}
if
limit
,
err
:=
strconv
.
Atoi
(
c
.
QueryParam
(
"limit"
));
err
==
nil
{
if
limit
,
err
:=
strconv
.
Atoi
(
c
.
QueryParam
(
"limit"
));
err
==
nil
{
resourceF
ind
.
Limit
=
&
limit
f
ind
.
Limit
=
&
limit
}
}
if
offset
,
err
:=
strconv
.
Atoi
(
c
.
QueryParam
(
"offset"
));
err
==
nil
{
if
offset
,
err
:=
strconv
.
Atoi
(
c
.
QueryParam
(
"offset"
));
err
==
nil
{
resourceF
ind
.
Offset
=
&
offset
f
ind
.
Offset
=
&
offset
}
}
list
,
err
:=
s
.
Store
.
FindResourceList
(
ctx
,
resourceF
ind
)
list
,
err
:=
s
.
Store
.
ListResources
(
ctx
,
f
ind
)
if
err
!=
nil
{
if
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to fetch resource list"
)
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to fetch resource list"
)
.
SetInternal
(
err
)
}
}
return
c
.
JSON
(
http
.
StatusOK
,
composeResponse
(
list
))
resourceMessageList
:=
[]
*
Resource
{}
for
_
,
resource
:=
range
list
{
resourceMessageList
=
append
(
resourceMessageList
,
convertResourceFromStore
(
resource
))
}
return
c
.
JSON
(
http
.
StatusOK
,
resourceMessageList
)
})
})
g
.
PATCH
(
"/resource/:resourceId"
,
func
(
c
echo
.
Context
)
error
{
g
.
PATCH
(
"/resource/:resourceId"
,
func
(
c
echo
.
Context
)
error
{
...
@@ -311,10 +360,9 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
...
@@ -311,10 +360,9 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
return
echo
.
NewHTTPError
(
http
.
StatusBadRequest
,
fmt
.
Sprintf
(
"ID is not a number: %s"
,
c
.
Param
(
"resourceId"
)))
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusBadRequest
,
fmt
.
Sprintf
(
"ID is not a number: %s"
,
c
.
Param
(
"resourceId"
)))
.
SetInternal
(
err
)
}
}
resource
Find
:=
&
api
.
ResourceFind
{
resource
,
err
:=
s
.
Store
.
GetResource
(
ctx
,
&
store
.
FindResource
{
ID
:
&
resourceID
,
ID
:
&
resourceID
,
}
})
resource
,
err
:=
s
.
Store
.
FindResource
(
ctx
,
resourceFind
)
if
err
!=
nil
{
if
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to find resource"
)
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to find resource"
)
.
SetInternal
(
err
)
}
}
...
@@ -322,25 +370,29 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
...
@@ -322,25 +370,29 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
return
echo
.
NewHTTPError
(
http
.
StatusUnauthorized
,
"Unauthorized"
)
return
echo
.
NewHTTPError
(
http
.
StatusUnauthorized
,
"Unauthorized"
)
}
}
request
:=
&
UpdateResourceRequest
{}
if
err
:=
json
.
NewDecoder
(
c
.
Request
()
.
Body
)
.
Decode
(
request
);
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusBadRequest
,
"Malformatted patch resource request"
)
.
SetInternal
(
err
)
}
currentTs
:=
time
.
Now
()
.
Unix
()
currentTs
:=
time
.
Now
()
.
Unix
()
resourcePatch
:=
&
api
.
ResourcePatch
{
update
:=
&
store
.
UpdateResource
{
ID
:
resourceID
,
UpdatedTs
:
&
currentTs
,
UpdatedTs
:
&
currentTs
,
}
}
if
err
:=
json
.
NewDecoder
(
c
.
Request
()
.
Body
)
.
Decode
(
resourcePatch
);
err
!=
nil
{
if
request
.
Filename
!=
nil
&&
*
request
.
Filename
!=
""
{
return
echo
.
NewHTTPError
(
http
.
StatusBadRequest
,
"Malformatted patch resource request"
)
.
SetInternal
(
err
)
update
.
Filename
=
request
.
Filename
}
}
if
request
.
ResetPublicID
!=
nil
&&
*
request
.
ResetPublicID
{
if
resourcePatch
.
ResetPublicID
!=
nil
&&
*
resourcePatch
.
ResetPublicID
{
publicID
:=
common
.
GenUUID
()
publicID
:=
common
.
GenUUID
()
resourcePatch
.
PublicID
=
&
publicID
update
.
PublicID
=
&
publicID
}
}
resourcePatch
.
ID
=
resourceID
resource
,
err
=
s
.
Store
.
UpdateResource
(
ctx
,
update
)
resource
,
err
=
s
.
Store
.
PatchResource
(
ctx
,
resourcePatch
)
if
err
!=
nil
{
if
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to patch resource"
)
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to patch resource"
)
.
SetInternal
(
err
)
}
}
return
c
.
JSON
(
http
.
StatusOK
,
co
mposeRespons
e
(
resource
))
return
c
.
JSON
(
http
.
StatusOK
,
co
nvertResourceFromStor
e
(
resource
))
})
})
g
.
DELETE
(
"/resource/:resourceId"
,
func
(
c
echo
.
Context
)
error
{
g
.
DELETE
(
"/resource/:resourceId"
,
func
(
c
echo
.
Context
)
error
{
...
@@ -355,15 +407,15 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
...
@@ -355,15 +407,15 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
return
echo
.
NewHTTPError
(
http
.
StatusBadRequest
,
fmt
.
Sprintf
(
"ID is not a number: %s"
,
c
.
Param
(
"resourceId"
)))
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusBadRequest
,
fmt
.
Sprintf
(
"ID is not a number: %s"
,
c
.
Param
(
"resourceId"
)))
.
SetInternal
(
err
)
}
}
resource
,
err
:=
s
.
Store
.
FindResource
(
ctx
,
&
api
.
ResourceFind
{
resource
,
err
:=
s
.
Store
.
GetResource
(
ctx
,
&
store
.
FindResource
{
ID
:
&
resourceID
,
ID
:
&
resourceID
,
CreatorID
:
&
userID
,
CreatorID
:
&
userID
,
})
})
if
err
!=
nil
{
if
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to find resource"
)
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to find resource"
)
.
SetInternal
(
err
)
}
}
if
resource
.
CreatorID
!=
userID
{
if
resource
==
nil
{
return
echo
.
NewHTTPError
(
http
.
Status
Unauthorized
,
"Unauthorize
d"
)
return
echo
.
NewHTTPError
(
http
.
Status
NotFound
,
"Resource not foun
d"
)
}
}
if
resource
.
InternalPath
!=
""
{
if
resource
.
InternalPath
!=
""
{
...
@@ -378,20 +430,16 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
...
@@ -378,20 +430,16 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
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
))
}
}
resourceDelete
:=
&
api
.
ResourceDelet
e
{
if
err
:=
s
.
Store
.
DeleteResourceV1
(
ctx
,
&
store
.
DeleteResourc
e
{
ID
:
resourceID
,
ID
:
resourceID
,
}
});
err
!=
nil
{
if
err
:=
s
.
Store
.
DeleteResource
(
ctx
,
resourceDelete
);
err
!=
nil
{
if
common
.
ErrorCode
(
err
)
==
common
.
NotFound
{
return
echo
.
NewHTTPError
(
http
.
StatusNotFound
,
fmt
.
Sprintf
(
"Resource ID not found: %d"
,
resourceID
))
}
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to delete resource"
)
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to delete resource"
)
.
SetInternal
(
err
)
}
}
return
c
.
JSON
(
http
.
StatusOK
,
true
)
return
c
.
JSON
(
http
.
StatusOK
,
true
)
})
})
}
}
func
(
s
*
Server
)
registerResourcePublicRoutes
(
g
*
echo
.
Group
)
{
func
(
s
*
APIV1Service
)
registerResourcePublicRoutes
(
g
*
echo
.
Group
)
{
f
:=
func
(
c
echo
.
Context
)
error
{
f
:=
func
(
c
echo
.
Context
)
error
{
ctx
:=
c
.
Request
()
.
Context
()
ctx
:=
c
.
Request
()
.
Context
()
resourceID
,
err
:=
strconv
.
Atoi
(
c
.
Param
(
"resourceId"
))
resourceID
,
err
:=
strconv
.
Atoi
(
c
.
Param
(
"resourceId"
))
...
@@ -399,7 +447,7 @@ func (s *Server) registerResourcePublicRoutes(g *echo.Group) {
...
@@ -399,7 +447,7 @@ func (s *Server) registerResourcePublicRoutes(g *echo.Group) {
return
echo
.
NewHTTPError
(
http
.
StatusBadRequest
,
fmt
.
Sprintf
(
"ID is not a number: %s"
,
c
.
Param
(
"resourceId"
)))
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusBadRequest
,
fmt
.
Sprintf
(
"ID is not a number: %s"
,
c
.
Param
(
"resourceId"
)))
.
SetInternal
(
err
)
}
}
resourceVisibility
,
err
:=
C
heckResourceVisibility
(
ctx
,
s
.
Store
,
resourceID
)
resourceVisibility
,
err
:=
c
heckResourceVisibility
(
ctx
,
s
.
Store
,
resourceID
)
if
err
!=
nil
{
if
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusBadRequest
,
"Failed to get resource visibility"
)
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusBadRequest
,
"Failed to get resource visibility"
)
.
SetInternal
(
err
)
}
}
...
@@ -410,11 +458,10 @@ func (s *Server) registerResourcePublicRoutes(g *echo.Group) {
...
@@ -410,11 +458,10 @@ func (s *Server) registerResourcePublicRoutes(g *echo.Group) {
return
echo
.
NewHTTPError
(
http
.
StatusUnauthorized
,
"Resource visibility not match"
)
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusUnauthorized
,
"Resource visibility not match"
)
.
SetInternal
(
err
)
}
}
resource
Find
:=
&
api
.
ResourceFind
{
resource
,
err
:=
s
.
Store
.
GetResource
(
ctx
,
&
store
.
FindResource
{
ID
:
&
resourceID
,
ID
:
&
resourceID
,
GetBlob
:
true
,
GetBlob
:
true
,
}
})
resource
,
err
:=
s
.
Store
.
FindResource
(
ctx
,
resourceFind
)
if
err
!=
nil
{
if
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
fmt
.
Sprintf
(
"Failed to find resource by ID: %v"
,
resourceID
))
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
fmt
.
Sprintf
(
"Failed to find resource by ID: %v"
,
resourceID
))
.
SetInternal
(
err
)
}
}
...
@@ -465,8 +512,8 @@ func (s *Server) registerResourcePublicRoutes(g *echo.Group) {
...
@@ -465,8 +512,8 @@ func (s *Server) registerResourcePublicRoutes(g *echo.Group) {
g
.
GET
(
"/r/:resourceId/*"
,
f
)
g
.
GET
(
"/r/:resourceId/*"
,
f
)
}
}
func
(
s
*
Server
)
createResourceCreateActivity
(
ctx
context
.
Context
,
resource
*
api
.
Resource
)
error
{
func
(
s
*
APIV1Service
)
createResourceCreateActivity
(
ctx
context
.
Context
,
resource
*
store
.
Resource
)
error
{
payload
:=
apiv1
.
ActivityResourceCreatePayload
{
payload
:=
ActivityResourceCreatePayload
{
Filename
:
resource
.
Filename
,
Filename
:
resource
.
Filename
,
Type
:
resource
.
Type
,
Type
:
resource
.
Type
,
Size
:
resource
.
Size
,
Size
:
resource
.
Size
,
...
@@ -477,8 +524,8 @@ func (s *Server) createResourceCreateActivity(ctx context.Context, resource *api
...
@@ -477,8 +524,8 @@ func (s *Server) createResourceCreateActivity(ctx context.Context, resource *api
}
}
activity
,
err
:=
s
.
Store
.
CreateActivity
(
ctx
,
&
store
.
ActivityMessage
{
activity
,
err
:=
s
.
Store
.
CreateActivity
(
ctx
,
&
store
.
ActivityMessage
{
CreatorID
:
resource
.
CreatorID
,
CreatorID
:
resource
.
CreatorID
,
Type
:
apiv1
.
ActivityResourceCreate
.
String
(),
Type
:
ActivityResourceCreate
.
String
(),
Level
:
apiv1
.
ActivityInfo
.
String
(),
Level
:
ActivityInfo
.
String
(),
Payload
:
string
(
payloadBytes
),
Payload
:
string
(
payloadBytes
),
})
})
if
err
!=
nil
||
activity
==
nil
{
if
err
!=
nil
||
activity
==
nil
{
...
@@ -560,12 +607,10 @@ func getOrGenerateThumbnailImage(srcBlob []byte, dstPath string) ([]byte, error)
...
@@ -560,12 +607,10 @@ func getOrGenerateThumbnailImage(srcBlob []byte, dstPath string) ([]byte, error)
return
dstBlob
,
nil
return
dstBlob
,
nil
}
}
func
C
heckResourceVisibility
(
ctx
context
.
Context
,
s
*
store
.
Store
,
resourceID
int
)
(
store
.
Visibility
,
error
)
{
func
c
heckResourceVisibility
(
ctx
context
.
Context
,
s
*
store
.
Store
,
resourceID
int
)
(
store
.
Visibility
,
error
)
{
memoResource
Find
:=
&
api
.
MemoResourceFind
{
memoResource
s
,
err
:=
s
.
ListMemoResources
(
ctx
,
&
store
.
FindMemoResource
{
ResourceID
:
&
resourceID
,
ResourceID
:
&
resourceID
,
}
})
memoResources
,
err
:=
s
.
FindMemoResourceList
(
ctx
,
memoResourceFind
)
if
err
!=
nil
{
if
err
!=
nil
{
return
store
.
Private
,
err
return
store
.
Private
,
err
}
}
...
@@ -604,3 +649,20 @@ func CheckResourceVisibility(ctx context.Context, s *store.Store, resourceID int
...
@@ -604,3 +649,20 @@ func CheckResourceVisibility(ctx context.Context, s *store.Store, resourceID int
// If all memo is PRIVATE, the resource do
// If all memo is PRIVATE, the resource do
return
store
.
Private
,
nil
return
store
.
Private
,
nil
}
}
func
convertResourceFromStore
(
resource
*
store
.
Resource
)
*
Resource
{
return
&
Resource
{
ID
:
resource
.
ID
,
CreatorID
:
resource
.
CreatorID
,
CreatedTs
:
resource
.
CreatedTs
,
UpdatedTs
:
resource
.
UpdatedTs
,
Filename
:
resource
.
Filename
,
Blob
:
resource
.
Blob
,
InternalPath
:
resource
.
InternalPath
,
ExternalLink
:
resource
.
ExternalLink
,
Type
:
resource
.
Type
,
Size
:
resource
.
Size
,
PublicID
:
resource
.
PublicID
,
LinkedMemoAmount
:
resource
.
LinkedMemoAmount
,
}
}
api/v1/v1.go
View file @
1fa9f162
...
@@ -34,4 +34,11 @@ func (s *APIV1Service) Register(rootGroup *echo.Group) {
...
@@ -34,4 +34,11 @@ func (s *APIV1Service) Register(rootGroup *echo.Group) {
s
.
registerTagRoutes
(
apiV1Group
)
s
.
registerTagRoutes
(
apiV1Group
)
s
.
registerShortcutRoutes
(
apiV1Group
)
s
.
registerShortcutRoutes
(
apiV1Group
)
s
.
registerStorageRoutes
(
apiV1Group
)
s
.
registerStorageRoutes
(
apiV1Group
)
s
.
registerResourceRoutes
(
apiV1Group
)
publicGroup
:=
rootGroup
.
Group
(
"/o"
)
publicGroup
.
Use
(
func
(
next
echo
.
HandlerFunc
)
echo
.
HandlerFunc
{
return
JWTMiddleware
(
s
,
next
,
s
.
Secret
)
})
s
.
registerResourcePublicRoutes
(
publicGroup
)
}
}
server/memo.go
View file @
1fa9f162
...
@@ -685,13 +685,15 @@ func (s *Server) composeMemoMessageToMemoResponse(ctx context.Context, memoMessa
...
@@ -685,13 +685,15 @@ func (s *Server) composeMemoMessageToMemoResponse(ctx context.Context, memoMessa
resourceList
:=
[]
*
api
.
Resource
{}
resourceList
:=
[]
*
api
.
Resource
{}
for
_
,
resourceID
:=
range
memoMessage
.
ResourceIDList
{
for
_
,
resourceID
:=
range
memoMessage
.
ResourceIDList
{
resource
,
err
:=
s
.
Store
.
FindResource
(
ctx
,
&
api
.
ResourceFind
{
resource
,
err
:=
s
.
Store
.
GetResource
(
ctx
,
&
store
.
FindResource
{
ID
:
&
resourceID
,
ID
:
&
resourceID
,
})
})
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
resourceList
=
append
(
resourceList
,
resource
)
if
resource
!=
nil
{
resourceList
=
append
(
resourceList
,
convertResourceFromStore
(
resource
))
}
}
}
memoResponse
.
ResourceList
=
resourceList
memoResponse
.
ResourceList
=
resourceList
...
@@ -714,3 +716,20 @@ func (s *Server) getMemoDisplayWithUpdatedTsSettingValue(ctx context.Context) (b
...
@@ -714,3 +716,20 @@ func (s *Server) getMemoDisplayWithUpdatedTsSettingValue(ctx context.Context) (b
}
}
return
memoDisplayWithUpdatedTs
,
nil
return
memoDisplayWithUpdatedTs
,
nil
}
}
func
convertResourceFromStore
(
resource
*
store
.
Resource
)
*
api
.
Resource
{
return
&
api
.
Resource
{
ID
:
resource
.
ID
,
CreatorID
:
resource
.
CreatorID
,
CreatedTs
:
resource
.
CreatedTs
,
UpdatedTs
:
resource
.
UpdatedTs
,
Filename
:
resource
.
Filename
,
Blob
:
resource
.
Blob
,
InternalPath
:
resource
.
InternalPath
,
ExternalLink
:
resource
.
ExternalLink
,
Type
:
resource
.
Type
,
Size
:
resource
.
Size
,
PublicID
:
resource
.
PublicID
,
LinkedMemoAmount
:
resource
.
LinkedMemoAmount
,
}
}
server/memo_resource.go
View file @
1fa9f162
...
@@ -29,10 +29,9 @@ func (s *Server) registerMemoResourceRoutes(g *echo.Group) {
...
@@ -29,10 +29,9 @@ func (s *Server) registerMemoResourceRoutes(g *echo.Group) {
if
err
:=
json
.
NewDecoder
(
c
.
Request
()
.
Body
)
.
Decode
(
memoResourceUpsert
);
err
!=
nil
{
if
err
:=
json
.
NewDecoder
(
c
.
Request
()
.
Body
)
.
Decode
(
memoResourceUpsert
);
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusBadRequest
,
"Malformatted post memo resource request"
)
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusBadRequest
,
"Malformatted post memo resource request"
)
.
SetInternal
(
err
)
}
}
resource
Find
:=
&
api
.
ResourceFind
{
resource
,
err
:=
s
.
Store
.
GetResource
(
ctx
,
&
store
.
FindResource
{
ID
:
&
memoResourceUpsert
.
ResourceID
,
ID
:
&
memoResourceUpsert
.
ResourceID
,
}
})
resource
,
err
:=
s
.
Store
.
FindResource
(
ctx
,
resourceFind
)
if
err
!=
nil
{
if
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to fetch resource"
)
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to fetch resource"
)
.
SetInternal
(
err
)
}
}
...
@@ -48,7 +47,7 @@ func (s *Server) registerMemoResourceRoutes(g *echo.Group) {
...
@@ -48,7 +47,7 @@ func (s *Server) registerMemoResourceRoutes(g *echo.Group) {
if
_
,
err
:=
s
.
Store
.
UpsertMemoResource
(
ctx
,
memoResourceUpsert
);
err
!=
nil
{
if
_
,
err
:=
s
.
Store
.
UpsertMemoResource
(
ctx
,
memoResourceUpsert
);
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to upsert memo resource"
)
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to upsert memo resource"
)
.
SetInternal
(
err
)
}
}
return
c
.
JSON
(
http
.
StatusOK
,
composeResponse
(
resource
)
)
return
c
.
JSON
(
http
.
StatusOK
,
true
)
})
})
g
.
GET
(
"/memo/:memoId/resource"
,
func
(
c
echo
.
Context
)
error
{
g
.
GET
(
"/memo/:memoId/resource"
,
func
(
c
echo
.
Context
)
error
{
...
@@ -58,13 +57,16 @@ func (s *Server) registerMemoResourceRoutes(g *echo.Group) {
...
@@ -58,13 +57,16 @@ func (s *Server) registerMemoResourceRoutes(g *echo.Group) {
return
echo
.
NewHTTPError
(
http
.
StatusBadRequest
,
fmt
.
Sprintf
(
"ID is not a number: %s"
,
c
.
Param
(
"memoId"
)))
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusBadRequest
,
fmt
.
Sprintf
(
"ID is not a number: %s"
,
c
.
Param
(
"memoId"
)))
.
SetInternal
(
err
)
}
}
resourceFind
:=
&
api
.
ResourceFind
{
list
,
err
:=
s
.
Store
.
ListResources
(
ctx
,
&
store
.
FindResource
{
MemoID
:
&
memoID
,
MemoID
:
&
memoID
,
}
})
resourceList
,
err
:=
s
.
Store
.
FindResourceList
(
ctx
,
resourceFind
)
if
err
!=
nil
{
if
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to fetch resource list"
)
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to fetch resource list"
)
.
SetInternal
(
err
)
}
}
resourceList
:=
[]
*
api
.
Resource
{}
for
_
,
resource
:=
range
list
{
resourceList
=
append
(
resourceList
,
convertResourceFromStore
(
resource
))
}
return
c
.
JSON
(
http
.
StatusOK
,
composeResponse
(
resourceList
))
return
c
.
JSON
(
http
.
StatusOK
,
composeResponse
(
resourceList
))
})
})
...
...
server/rss.go
View file @
1fa9f162
...
@@ -11,7 +11,6 @@ import (
...
@@ -11,7 +11,6 @@ import (
"github.com/gorilla/feeds"
"github.com/gorilla/feeds"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4"
"github.com/usememos/memos/api"
apiv1
"github.com/usememos/memos/api/v1"
apiv1
"github.com/usememos/memos/api/v1"
"github.com/usememos/memos/common"
"github.com/usememos/memos/common"
"github.com/usememos/memos/store"
"github.com/usememos/memos/store"
...
@@ -102,7 +101,7 @@ func (s *Server) generateRSSFromMemoList(ctx context.Context, memoList []*store.
...
@@ -102,7 +101,7 @@ func (s *Server) generateRSSFromMemoList(ctx context.Context, memoList []*store.
}
}
if
len
(
memo
.
ResourceIDList
)
>
0
{
if
len
(
memo
.
ResourceIDList
)
>
0
{
resourceID
:=
memo
.
ResourceIDList
[
0
]
resourceID
:=
memo
.
ResourceIDList
[
0
]
resource
,
err
:=
s
.
Store
.
FindResource
(
ctx
,
&
api
.
ResourceFind
{
resource
,
err
:=
s
.
Store
.
GetResource
(
ctx
,
&
store
.
FindResource
{
ID
:
&
resourceID
,
ID
:
&
resourceID
,
})
})
if
err
!=
nil
{
if
err
!=
nil
{
...
...
server/server.go
View file @
1fa9f162
...
@@ -92,7 +92,6 @@ func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store
...
@@ -92,7 +92,6 @@ func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store
return
JWTMiddleware
(
s
,
next
,
s
.
Secret
)
return
JWTMiddleware
(
s
,
next
,
s
.
Secret
)
})
})
registerGetterPublicRoutes
(
publicGroup
)
registerGetterPublicRoutes
(
publicGroup
)
s
.
registerResourcePublicRoutes
(
publicGroup
)
apiGroup
:=
e
.
Group
(
"/api"
)
apiGroup
:=
e
.
Group
(
"/api"
)
apiGroup
.
Use
(
func
(
next
echo
.
HandlerFunc
)
echo
.
HandlerFunc
{
apiGroup
.
Use
(
func
(
next
echo
.
HandlerFunc
)
echo
.
HandlerFunc
{
...
@@ -100,7 +99,6 @@ func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store
...
@@ -100,7 +99,6 @@ func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store
})
})
s
.
registerMemoRoutes
(
apiGroup
)
s
.
registerMemoRoutes
(
apiGroup
)
s
.
registerMemoResourceRoutes
(
apiGroup
)
s
.
registerMemoResourceRoutes
(
apiGroup
)
s
.
registerResourceRoutes
(
apiGroup
)
s
.
registerMemoRelationRoutes
(
apiGroup
)
s
.
registerMemoRelationRoutes
(
apiGroup
)
apiV1Service
:=
apiv1
.
NewAPIV1Service
(
s
.
Secret
,
profile
,
store
)
apiV1Service
:=
apiv1
.
NewAPIV1Service
(
s
.
Secret
,
profile
,
store
)
...
...
server/telegram.go
View file @
1fa9f162
...
@@ -90,15 +90,14 @@ func (t *telegramHandler) MessageHandle(ctx context.Context, bot *telegram.Bot,
...
@@ -90,15 +90,14 @@ func (t *telegramHandler) MessageHandle(ctx context.Context, bot *telegram.Bot,
case
".png"
:
case
".png"
:
mime
=
"image/png"
mime
=
"image/png"
}
}
resource
Create
:=
api
.
ResourceCreat
e
{
resource
,
err
:=
t
.
store
.
CreateResourceV1
(
ctx
,
&
store
.
Resourc
e
{
CreatorID
:
creatorID
,
CreatorID
:
creatorID
,
Filename
:
filename
,
Filename
:
filename
,
Type
:
mime
,
Type
:
mime
,
Size
:
int64
(
len
(
blob
)),
Size
:
int64
(
len
(
blob
)),
Blob
:
blob
,
Blob
:
blob
,
PublicID
:
common
.
GenUUID
(),
PublicID
:
common
.
GenUUID
(),
}
})
resource
,
err
:=
t
.
store
.
CreateResource
(
ctx
,
&
resourceCreate
)
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
)
return
err
return
err
...
...
store/memo_resource.go
View file @
1fa9f162
...
@@ -10,6 +10,85 @@ import (
...
@@ -10,6 +10,85 @@ import (
"github.com/usememos/memos/common"
"github.com/usememos/memos/common"
)
)
type
MemoResource
struct
{
MemoID
int
ResourceID
int
CreatedTs
int64
UpdatedTs
int64
}
type
FindMemoResource
struct
{
MemoID
*
int
ResourceID
*
int
}
func
(
s
*
Store
)
ListMemoResources
(
ctx
context
.
Context
,
find
*
FindMemoResource
)
([]
*
MemoResource
,
error
)
{
tx
,
err
:=
s
.
db
.
BeginTx
(
ctx
,
nil
)
if
err
!=
nil
{
return
nil
,
err
}
defer
tx
.
Rollback
()
list
,
err
:=
listMemoResources
(
ctx
,
tx
,
find
)
if
err
!=
nil
{
return
nil
,
err
}
if
err
:=
tx
.
Commit
();
err
!=
nil
{
return
nil
,
err
}
return
list
,
nil
}
func
listMemoResources
(
ctx
context
.
Context
,
tx
*
sql
.
Tx
,
find
*
FindMemoResource
)
([]
*
MemoResource
,
error
)
{
where
,
args
:=
[]
string
{
"1 = 1"
},
[]
any
{}
if
v
:=
find
.
MemoID
;
v
!=
nil
{
where
,
args
=
append
(
where
,
"memo_id = ?"
),
append
(
args
,
*
v
)
}
if
v
:=
find
.
ResourceID
;
v
!=
nil
{
where
,
args
=
append
(
where
,
"resource_id = ?"
),
append
(
args
,
*
v
)
}
query
:=
`
SELECT
memo_id,
resource_id,
created_ts,
updated_ts
FROM memo_resource
WHERE `
+
strings
.
Join
(
where
,
" AND "
)
+
`
ORDER BY updated_ts DESC
`
rows
,
err
:=
tx
.
QueryContext
(
ctx
,
query
,
args
...
)
if
err
!=
nil
{
return
nil
,
FormatError
(
err
)
}
defer
rows
.
Close
()
list
:=
make
([]
*
MemoResource
,
0
)
for
rows
.
Next
()
{
var
memoResource
MemoResource
if
err
:=
rows
.
Scan
(
&
memoResource
.
MemoID
,
&
memoResource
.
ResourceID
,
&
memoResource
.
CreatedTs
,
&
memoResource
.
UpdatedTs
,
);
err
!=
nil
{
return
nil
,
FormatError
(
err
)
}
list
=
append
(
list
,
&
memoResource
)
}
if
err
:=
rows
.
Err
();
err
!=
nil
{
return
nil
,
err
}
return
list
,
nil
}
// memoResourceRaw is the store model for an MemoResource.
// memoResourceRaw is the store model for an MemoResource.
// Fields have exactly the same meanings as MemoResource.
// Fields have exactly the same meanings as MemoResource.
type
memoResourceRaw
struct
{
type
memoResourceRaw
struct
{
...
...
store/resource.go
View file @
1fa9f162
...
@@ -5,14 +5,9 @@ import (
...
@@ -5,14 +5,9 @@ import (
"database/sql"
"database/sql"
"fmt"
"fmt"
"strings"
"strings"
"github.com/usememos/memos/api"
"github.com/usememos/memos/common"
)
)
// resourceRaw is the store model for an Resource.
type
Resource
struct
{
// Fields have exactly the same meanings as Resource.
type
resourceRaw
struct
{
ID
int
ID
int
// Standard fields
// Standard fields
...
@@ -31,217 +26,177 @@ type resourceRaw struct {
...
@@ -31,217 +26,177 @@ type resourceRaw struct {
LinkedMemoAmount
int
LinkedMemoAmount
int
}
}
func
(
raw
*
resourceRaw
)
toResource
()
*
api
.
Resource
{
type
FindResource
struct
{
return
&
api
.
Resource
{
GetBlob
bool
ID
:
raw
.
ID
,
ID
*
int
CreatorID
*
int
// Standard fields
Filename
*
string
CreatorID
:
raw
.
CreatorID
,
MemoID
*
int
CreatedTs
:
raw
.
CreatedTs
,
PublicID
*
string
UpdatedTs
:
raw
.
UpdatedTs
,
Limit
*
int
Offset
*
int
// Domain specific fields
Filename
:
raw
.
Filename
,
Blob
:
raw
.
Blob
,
InternalPath
:
raw
.
InternalPath
,
ExternalLink
:
raw
.
ExternalLink
,
Type
:
raw
.
Type
,
Size
:
raw
.
Size
,
PublicID
:
raw
.
PublicID
,
LinkedMemoAmount
:
raw
.
LinkedMemoAmount
,
}
}
}
func
(
s
*
Store
)
CreateResource
(
ctx
context
.
Context
,
create
*
api
.
ResourceCreate
)
(
*
api
.
Resource
,
error
)
{
type
UpdateResource
struct
{
tx
,
err
:=
s
.
db
.
BeginTx
(
ctx
,
nil
)
ID
int
if
err
!=
nil
{
UpdatedTs
*
int64
return
nil
,
FormatError
(
err
)
Filename
*
string
}
PublicID
*
string
defer
tx
.
Rollback
()
}
resourceRaw
,
err
:=
createResourceImpl
(
ctx
,
tx
,
create
)
if
err
!=
nil
{
return
nil
,
err
}
if
err
:=
tx
.
Commit
();
err
!=
nil
{
return
nil
,
FormatError
(
err
)
}
resource
:=
resourceRaw
.
toResource
()
return
resource
,
nil
type
DeleteResource
struct
{
ID
int
}
}
func
(
s
*
Store
)
PatchResource
(
ctx
context
.
Context
,
patch
*
api
.
ResourcePatch
)
(
*
api
.
Resource
,
error
)
{
func
(
s
*
Store
)
CreateResourceV1
(
ctx
context
.
Context
,
create
*
Resource
)
(
*
Resource
,
error
)
{
tx
,
err
:=
s
.
db
.
BeginTx
(
ctx
,
nil
)
tx
,
err
:=
s
.
db
.
BeginTx
(
ctx
,
nil
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
FormatError
(
err
)
return
nil
,
FormatError
(
err
)
}
}
defer
tx
.
Rollback
()
defer
tx
.
Rollback
()
resourceRaw
,
err
:=
patchResourceImpl
(
ctx
,
tx
,
patch
)
if
err
:=
tx
.
QueryRowContext
(
ctx
,
`
if
err
!=
nil
{
INSERT INTO resource (
filename,
blob,
external_link,
type,
size,
creator_id,
internal_path,
public_id
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
RETURNING id, created_ts, updated_ts
`
,
create
.
Filename
,
create
.
Blob
,
create
.
ExternalLink
,
create
.
Type
,
create
.
Size
,
create
.
CreatorID
,
create
.
InternalPath
,
create
.
PublicID
,
)
.
Scan
(
&
create
.
ID
,
&
create
.
CreatedTs
,
&
create
.
UpdatedTs
);
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
if
err
:=
tx
.
Commit
();
err
!=
nil
{
if
err
:=
tx
.
Commit
();
err
!=
nil
{
return
nil
,
FormatError
(
err
)
return
nil
,
err
}
}
s
.
resourceCache
.
Store
(
resourceRaw
.
ID
,
resourceRaw
)
resource
:=
create
resource
:=
resourceRaw
.
toResource
()
return
resource
,
nil
return
resource
,
nil
}
}
func
(
s
*
Store
)
FindResourceList
(
ctx
context
.
Context
,
find
*
api
.
ResourceFind
)
([]
*
api
.
Resource
,
error
)
{
func
(
s
*
Store
)
ListResources
(
ctx
context
.
Context
,
find
*
FindResource
)
([]
*
Resource
,
error
)
{
tx
,
err
:=
s
.
db
.
BeginTx
(
ctx
,
nil
)
tx
,
err
:=
s
.
db
.
BeginTx
(
ctx
,
nil
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
FormatError
(
err
)
return
nil
,
FormatError
(
err
)
}
}
defer
tx
.
Rollback
()
defer
tx
.
Rollback
()
resource
RawList
,
err
:=
findResourceListImpl
(
ctx
,
tx
,
find
)
resource
s
,
err
:=
listResources
(
ctx
,
tx
,
find
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
resourceList
:=
[]
*
api
.
Resource
{}
if
err
:=
tx
.
Commit
();
err
!=
nil
{
for
_
,
raw
:=
range
resourceRawList
{
return
nil
,
err
if
!
find
.
GetBlob
{
s
.
resourceCache
.
Store
(
raw
.
ID
,
raw
)
}
resourceList
=
append
(
resourceList
,
raw
.
toResource
())
}
}
return
resource
List
,
nil
return
resource
s
,
nil
}
}
func
(
s
*
Store
)
FindResource
(
ctx
context
.
Context
,
find
*
api
.
ResourceFind
)
(
*
api
.
Resource
,
error
)
{
func
(
s
*
Store
)
GetResource
(
ctx
context
.
Context
,
find
*
FindResource
)
(
*
Resource
,
error
)
{
if
!
find
.
GetBlob
&&
find
.
ID
!=
nil
{
if
raw
,
ok
:=
s
.
resourceCache
.
Load
(
find
.
ID
);
ok
{
return
raw
.
(
*
resourceRaw
)
.
toResource
(),
nil
}
}
tx
,
err
:=
s
.
db
.
BeginTx
(
ctx
,
nil
)
tx
,
err
:=
s
.
db
.
BeginTx
(
ctx
,
nil
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
FormatError
(
err
)
return
nil
,
FormatError
(
err
)
}
}
defer
tx
.
Rollback
()
defer
tx
.
Rollback
()
list
,
err
:=
findResourceListImpl
(
ctx
,
tx
,
find
)
resources
,
err
:=
listResources
(
ctx
,
tx
,
find
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
if
len
(
list
)
==
0
{
if
err
:=
tx
.
Commit
();
err
!=
nil
{
return
nil
,
&
common
.
Error
{
Code
:
common
.
NotFound
,
Err
:
fmt
.
Errorf
(
"not found"
)}
return
nil
,
err
}
}
resourceRaw
:=
list
[
0
]
if
len
(
resources
)
==
0
{
if
!
find
.
GetBlob
{
return
nil
,
nil
s
.
resourceCache
.
Store
(
resourceRaw
.
ID
,
resourceRaw
)
}
}
resource
:=
resourceRaw
.
toResource
()
return
resource
,
nil
return
resource
s
[
0
]
,
nil
}
}
func
(
s
*
Store
)
DeleteResource
(
ctx
context
.
Context
,
delete
*
api
.
ResourceDelete
)
error
{
func
(
s
*
Store
)
UpdateResource
(
ctx
context
.
Context
,
update
*
UpdateResource
)
(
*
Resource
,
error
)
{
tx
,
err
:=
s
.
db
.
BeginTx
(
ctx
,
nil
)
tx
,
err
:=
s
.
db
.
BeginTx
(
ctx
,
nil
)
if
err
!=
nil
{
if
err
!=
nil
{
return
FormatError
(
err
)
}
defer
tx
.
Rollback
()
if
err
:=
deleteResource
(
ctx
,
tx
,
delete
);
err
!=
nil
{
return
err
}
if
err
:=
s
.
vacuumImpl
(
ctx
,
tx
);
err
!=
nil
{
return
err
}
if
err
:=
tx
.
Commit
();
err
!=
nil
{
return
FormatError
(
err
)
}
s
.
resourceCache
.
Delete
(
delete
.
ID
)
return
nil
}
func
createResourceImpl
(
ctx
context
.
Context
,
tx
*
sql
.
Tx
,
create
*
api
.
ResourceCreate
)
(
*
resourceRaw
,
error
)
{
fields
:=
[]
string
{
"filename"
,
"blob"
,
"external_link"
,
"type"
,
"size"
,
"creator_id"
,
"internal_path"
,
"public_id"
}
values
:=
[]
any
{
create
.
Filename
,
create
.
Blob
,
create
.
ExternalLink
,
create
.
Type
,
create
.
Size
,
create
.
CreatorID
,
create
.
InternalPath
,
create
.
PublicID
}
placeholders
:=
[]
string
{
"?"
,
"?"
,
"?"
,
"?"
,
"?"
,
"?"
,
"?"
,
"?"
}
query
:=
`
INSERT INTO resource (
`
+
strings
.
Join
(
fields
,
","
)
+
`
)
VALUES (`
+
strings
.
Join
(
placeholders
,
","
)
+
`)
RETURNING id, `
+
strings
.
Join
(
fields
,
","
)
+
`, created_ts, updated_ts
`
var
resourceRaw
resourceRaw
dests
:=
[]
any
{
&
resourceRaw
.
ID
,
&
resourceRaw
.
Filename
,
&
resourceRaw
.
Blob
,
&
resourceRaw
.
ExternalLink
,
&
resourceRaw
.
Type
,
&
resourceRaw
.
Size
,
&
resourceRaw
.
CreatorID
,
&
resourceRaw
.
InternalPath
,
&
resourceRaw
.
PublicID
,
}
dests
=
append
(
dests
,
[]
any
{
&
resourceRaw
.
CreatedTs
,
&
resourceRaw
.
UpdatedTs
}
...
)
if
err
:=
tx
.
QueryRowContext
(
ctx
,
query
,
values
...
)
.
Scan
(
dests
...
);
err
!=
nil
{
return
nil
,
FormatError
(
err
)
return
nil
,
FormatError
(
err
)
}
}
defer
tx
.
Rollback
()
return
&
resourceRaw
,
nil
}
func
patchResourceImpl
(
ctx
context
.
Context
,
tx
*
sql
.
Tx
,
patch
*
api
.
ResourcePatch
)
(
*
resourceRaw
,
error
)
{
set
,
args
:=
[]
string
{},
[]
any
{}
set
,
args
:=
[]
string
{},
[]
any
{}
if
v
:=
patch
.
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
:=
patch
.
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
:=
patch
.
PublicID
;
v
!=
nil
{
if
v
:=
update
.
PublicID
;
v
!=
nil
{
set
,
args
=
append
(
set
,
"public_id = ?"
),
append
(
args
,
*
v
)
set
,
args
=
append
(
set
,
"public_id = ?"
),
append
(
args
,
*
v
)
}
}
args
=
append
(
args
,
patch
.
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"
,
"public_id"
}
query
:=
`
query
:=
`
UPDATE resource
UPDATE resource
SET `
+
strings
.
Join
(
set
,
", "
)
+
`
SET `
+
strings
.
Join
(
set
,
", "
)
+
`
WHERE id = ?
WHERE id = ?
RETURNING `
+
strings
.
Join
(
fields
,
", "
)
RETURNING `
+
strings
.
Join
(
fields
,
", "
)
var
resourceRaw
resourceRaw
resource
:=
Resource
{}
dests
:=
[]
any
{
dests
:=
[]
any
{
&
resource
Raw
.
ID
,
&
resource
.
ID
,
&
resource
Raw
.
Filename
,
&
resource
.
Filename
,
&
resource
Raw
.
ExternalLink
,
&
resource
.
ExternalLink
,
&
resource
Raw
.
Type
,
&
resource
.
Type
,
&
resource
Raw
.
Size
,
&
resource
.
Size
,
&
resource
Raw
.
CreatorID
,
&
resource
.
CreatorID
,
&
resource
Raw
.
CreatedTs
,
&
resource
.
CreatedTs
,
&
resource
Raw
.
UpdatedTs
,
&
resource
.
UpdatedTs
,
&
resource
Raw
.
InternalPath
,
&
resource
.
InternalPath
,
&
resource
Raw
.
PublicID
,
&
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
,
FormatError
(
err
)
return
nil
,
FormatError
(
err
)
}
}
return
&
resourceRaw
,
nil
if
err
:=
tx
.
Commit
();
err
!=
nil
{
return
nil
,
err
}
return
&
resource
,
nil
}
func
(
s
*
Store
)
DeleteResourceV1
(
ctx
context
.
Context
,
delete
*
DeleteResource
)
error
{
tx
,
err
:=
s
.
db
.
BeginTx
(
ctx
,
nil
)
if
err
!=
nil
{
return
FormatError
(
err
)
}
defer
tx
.
Rollback
()
if
_
,
err
:=
tx
.
ExecContext
(
ctx
,
`
DELETE FROM resource
WHERE id = ?
`
,
delete
.
ID
);
err
!=
nil
{
return
err
}
if
err
:=
tx
.
Commit
();
err
!=
nil
{
// Prevent linter warning.
return
err
}
return
nil
}
}
func
findResourceListImpl
(
ctx
context
.
Context
,
tx
*
sql
.
Tx
,
find
*
api
.
ResourceFind
)
([]
*
resourceRaw
,
error
)
{
func
listResources
(
ctx
context
.
Context
,
tx
*
sql
.
Tx
,
find
*
FindResource
)
([]
*
Resource
,
error
)
{
where
,
args
:=
[]
string
{
"1 = 1"
},
[]
any
{}
where
,
args
:=
[]
string
{
"1 = 1"
},
[]
any
{}
if
v
:=
find
.
ID
;
v
!=
nil
{
if
v
:=
find
.
ID
;
v
!=
nil
{
...
@@ -288,53 +243,36 @@ func findResourceListImpl(ctx context.Context, tx *sql.Tx, find *api.ResourceFin
...
@@ -288,53 +243,36 @@ func findResourceListImpl(ctx context.Context, tx *sql.Tx, find *api.ResourceFin
}
}
defer
rows
.
Close
()
defer
rows
.
Close
()
resourceRawList
:=
make
([]
*
resourceRaw
,
0
)
list
:=
make
([]
*
Resource
,
0
)
for
rows
.
Next
()
{
for
rows
.
Next
()
{
var
resourceRaw
resourceRaw
resource
:=
Resource
{}
dests
:=
[]
any
{
dests
:=
[]
any
{
&
resource
Raw
.
LinkedMemoAmount
,
&
resource
.
LinkedMemoAmount
,
&
resource
Raw
.
ID
,
&
resource
.
ID
,
&
resource
Raw
.
Filename
,
&
resource
.
Filename
,
&
resource
Raw
.
ExternalLink
,
&
resource
.
ExternalLink
,
&
resource
Raw
.
Type
,
&
resource
.
Type
,
&
resource
Raw
.
Size
,
&
resource
.
Size
,
&
resource
Raw
.
CreatorID
,
&
resource
.
CreatorID
,
&
resource
Raw
.
CreatedTs
,
&
resource
.
CreatedTs
,
&
resource
Raw
.
UpdatedTs
,
&
resource
.
UpdatedTs
,
&
resource
Raw
.
InternalPath
,
&
resource
.
InternalPath
,
&
resource
Raw
.
PublicID
,
&
resource
.
PublicID
,
}
}
if
find
.
GetBlob
{
if
find
.
GetBlob
{
dests
=
append
(
dests
,
&
resource
Raw
.
Blob
)
dests
=
append
(
dests
,
&
resource
.
Blob
)
}
}
if
err
:=
rows
.
Scan
(
dests
...
);
err
!=
nil
{
if
err
:=
rows
.
Scan
(
dests
...
);
err
!=
nil
{
return
nil
,
FormatError
(
err
)
return
nil
,
FormatError
(
err
)
}
}
resourceRawList
=
append
(
resourceRawList
,
&
resourceRaw
)
list
=
append
(
list
,
&
resource
)
}
}
if
err
:=
rows
.
Err
();
err
!=
nil
{
if
err
:=
rows
.
Err
();
err
!=
nil
{
return
nil
,
FormatError
(
err
)
return
nil
,
FormatError
(
err
)
}
}
return
resourceRawList
,
nil
return
list
,
nil
}
func
deleteResource
(
ctx
context
.
Context
,
tx
*
sql
.
Tx
,
delete
*
api
.
ResourceDelete
)
error
{
where
,
args
:=
[]
string
{
"id = ?"
},
[]
any
{
delete
.
ID
}
stmt
:=
`DELETE FROM resource WHERE `
+
strings
.
Join
(
where
,
" AND "
)
result
,
err
:=
tx
.
ExecContext
(
ctx
,
stmt
,
args
...
)
if
err
!=
nil
{
return
FormatError
(
err
)
}
rows
,
_
:=
result
.
RowsAffected
()
if
rows
==
0
{
return
&
common
.
Error
{
Code
:
common
.
NotFound
,
Err
:
fmt
.
Errorf
(
"resource not found"
)}
}
return
nil
}
}
func
vacuumResource
(
ctx
context
.
Context
,
tx
*
sql
.
Tx
)
error
{
func
vacuumResource
(
ctx
context
.
Context
,
tx
*
sql
.
Tx
)
error
{
...
...
store/store.go
View file @
1fa9f162
...
@@ -17,7 +17,6 @@ type Store struct {
...
@@ -17,7 +17,6 @@ type Store struct {
userSettingCache
sync
.
Map
// map[string]*UserSetting
userSettingCache
sync
.
Map
// map[string]*UserSetting
shortcutCache
sync
.
Map
// map[int]*shortcutRaw
shortcutCache
sync
.
Map
// map[int]*shortcutRaw
idpCache
sync
.
Map
// map[int]*IdentityProvider
idpCache
sync
.
Map
// map[int]*IdentityProvider
resourceCache
sync
.
Map
// map[int]*resourceRaw
}
}
// New creates a new instance of Store.
// New creates a new instance of Store.
...
...
test/store/resource_test.go
View file @
1fa9f162
...
@@ -5,13 +5,13 @@ import (
...
@@ -5,13 +5,13 @@ import (
"testing"
"testing"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/require"
"github.com/usememos/memos/
api
"
"github.com/usememos/memos/
store
"
)
)
func
TestResourceStore
(
t
*
testing
.
T
)
{
func
TestResourceStore
(
t
*
testing
.
T
)
{
ctx
:=
context
.
Background
()
ctx
:=
context
.
Background
()
store
:=
NewTestingStore
(
ctx
,
t
)
ts
:=
NewTestingStore
(
ctx
,
t
)
_
,
err
:=
store
.
CreateResource
(
ctx
,
&
api
.
ResourceCreat
e
{
_
,
err
:=
ts
.
CreateResourceV1
(
ctx
,
&
store
.
Resourc
e
{
CreatorID
:
101
,
CreatorID
:
101
,
Filename
:
"test.epub"
,
Filename
:
"test.epub"
,
Blob
:
[]
byte
(
"test"
),
Blob
:
[]
byte
(
"test"
),
...
@@ -25,34 +25,36 @@ func TestResourceStore(t *testing.T) {
...
@@ -25,34 +25,36 @@ func TestResourceStore(t *testing.T) {
correctFilename
:=
"test.epub"
correctFilename
:=
"test.epub"
incorrectFilename
:=
"test.png"
incorrectFilename
:=
"test.png"
res
,
err
:=
store
.
FindResource
(
ctx
,
&
api
.
ResourceFind
{
res
,
err
:=
ts
.
GetResource
(
ctx
,
&
store
.
FindResource
{
Filename
:
&
correctFilename
,
Filename
:
&
correctFilename
,
})
})
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
correctFilename
,
res
.
Filename
)
require
.
Equal
(
t
,
correctFilename
,
res
.
Filename
)
require
.
Equal
(
t
,
1
,
res
.
ID
)
require
.
Equal
(
t
,
1
,
res
.
ID
)
_
,
err
=
store
.
FindResource
(
ctx
,
&
api
.
ResourceFind
{
notFoundResource
,
err
:=
ts
.
GetResource
(
ctx
,
&
store
.
FindResource
{
Filename
:
&
incorrectFilename
,
Filename
:
&
incorrectFilename
,
})
})
require
.
Error
(
t
,
err
)
require
.
NoError
(
t
,
err
)
require
.
Nil
(
t
,
notFoundResource
)
correctCreatorID
:=
101
correctCreatorID
:=
101
incorrectCreatorID
:=
102
incorrectCreatorID
:=
102
_
,
err
=
store
.
FindResource
(
ctx
,
&
api
.
ResourceFind
{
_
,
err
=
ts
.
GetResource
(
ctx
,
&
store
.
FindResource
{
CreatorID
:
&
correctCreatorID
,
CreatorID
:
&
correctCreatorID
,
})
})
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
_
,
err
=
store
.
FindResource
(
ctx
,
&
api
.
ResourceFind
{
notFoundResource
,
err
=
ts
.
GetResource
(
ctx
,
&
store
.
FindResource
{
CreatorID
:
&
incorrectCreatorID
,
CreatorID
:
&
incorrectCreatorID
,
})
})
require
.
Error
(
t
,
err
)
require
.
NoError
(
t
,
err
)
require
.
Nil
(
t
,
notFoundResource
)
err
=
store
.
DeleteResource
(
ctx
,
&
api
.
ResourceDelet
e
{
err
=
ts
.
DeleteResourceV1
(
ctx
,
&
store
.
DeleteResourc
e
{
ID
:
1
,
ID
:
1
,
})
})
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
err
=
store
.
DeleteResource
(
ctx
,
&
api
.
ResourceDelet
e
{
err
=
ts
.
DeleteResourceV1
(
ctx
,
&
store
.
DeleteResourc
e
{
ID
:
2
,
ID
:
2
,
})
})
require
.
Error
(
t
,
err
)
require
.
No
Error
(
t
,
err
)
}
}
web/src/helpers/api.ts
View file @
1fa9f162
...
@@ -161,7 +161,7 @@ export function deleteShortcutById(shortcutId: ShortcutId) {
...
@@ -161,7 +161,7 @@ export function deleteShortcutById(shortcutId: ShortcutId) {
}
}
export
function
getResourceList
()
{
export
function
getResourceList
()
{
return
axios
.
get
<
Res
ponseObject
<
Resource
[]
>>
(
"/api
/resource"
);
return
axios
.
get
<
Res
ource
[]
>
(
"/api/v1
/resource"
);
}
}
export
function
getResourceListWithLimit
(
resourceFind
?:
ResourceFind
)
{
export
function
getResourceListWithLimit
(
resourceFind
?:
ResourceFind
)
{
...
@@ -172,23 +172,23 @@ export function getResourceListWithLimit(resourceFind?: ResourceFind) {
...
@@ -172,23 +172,23 @@ export function getResourceListWithLimit(resourceFind?: ResourceFind) {
if
(
resourceFind
?.
limit
)
{
if
(
resourceFind
?.
limit
)
{
queryList
.
push
(
`limit=
${
resourceFind
.
limit
}
`
);
queryList
.
push
(
`limit=
${
resourceFind
.
limit
}
`
);
}
}
return
axios
.
get
<
Res
ponseObject
<
Resource
[]
>>
(
`/api
/resource?
${
queryList
.
join
(
"&"
)}
`
);
return
axios
.
get
<
Res
ource
[]
>
(
`/api/v1
/resource?
${
queryList
.
join
(
"&"
)}
`
);
}
}
export
function
createResource
(
resourceCreate
:
ResourceCreate
)
{
export
function
createResource
(
resourceCreate
:
ResourceCreate
)
{
return
axios
.
post
<
Res
ponseObject
<
Resource
>>
(
"/api
/resource"
,
resourceCreate
);
return
axios
.
post
<
Res
ource
>
(
"/api/v1
/resource"
,
resourceCreate
);
}
}
export
function
createResourceWithBlob
(
formData
:
FormData
)
{
export
function
createResourceWithBlob
(
formData
:
FormData
)
{
return
axios
.
post
<
Res
ponseObject
<
Resource
>>
(
"/api
/resource/blob"
,
formData
);
return
axios
.
post
<
Res
ource
>
(
"/api/v1
/resource/blob"
,
formData
);
}
}
export
function
deleteResourceById
(
id
:
ResourceId
)
{
export
function
patchResource
(
resourcePatch
:
ResourcePatch
)
{
return
axios
.
delete
(
`/api/resource/
${
id
}
`
);
return
axios
.
patch
<
Resource
>
(
`/api/v1/resource/
${
resourcePatch
.
id
}
`
,
resourcePatch
);
}
}
export
function
patchResource
(
resourcePatch
:
ResourcePatch
)
{
export
function
deleteResourceById
(
id
:
ResourceId
)
{
return
axios
.
patch
<
ResponseObject
<
Resource
>>
(
`/api/resource/
${
resourcePatch
.
id
}
`
,
resourcePatch
);
return
axios
.
delete
(
`/api/v1/resource/
${
id
}
`
);
}
}
export
function
getMemoResourceList
(
memoId
:
MemoId
)
{
export
function
getMemoResourceList
(
memoId
:
MemoId
)
{
...
@@ -196,7 +196,7 @@ export function getMemoResourceList(memoId: MemoId) {
...
@@ -196,7 +196,7 @@ export function getMemoResourceList(memoId: MemoId) {
}
}
export
function
upsertMemoResource
(
memoId
:
MemoId
,
resourceId
:
ResourceId
)
{
export
function
upsertMemoResource
(
memoId
:
MemoId
,
resourceId
:
ResourceId
)
{
return
axios
.
post
<
ResponseObject
<
Resource
>>
(
`/api/memo/
${
memoId
}
/resource`
,
{
return
axios
.
post
(
`/api/memo/
${
memoId
}
/resource`
,
{
resourceId
,
resourceId
,
});
});
}
}
...
...
web/src/store/module/resource.ts
View file @
1fa9f162
...
@@ -25,7 +25,7 @@ export const useResourceStore = () => {
...
@@ -25,7 +25,7 @@ export const useResourceStore = () => {
return
store
.
getState
().
resource
;
return
store
.
getState
().
resource
;
},
},
async
fetchResourceList
():
Promise
<
Resource
[]
>
{
async
fetchResourceList
():
Promise
<
Resource
[]
>
{
const
{
data
}
=
(
await
api
.
getResourceList
()).
data
;
const
{
data
}
=
await
api
.
getResourceList
()
;
const
resourceList
=
data
.
map
((
m
)
=>
convertResponseModelResource
(
m
));
const
resourceList
=
data
.
map
((
m
)
=>
convertResponseModelResource
(
m
));
store
.
dispatch
(
setResources
(
resourceList
));
store
.
dispatch
(
setResources
(
resourceList
));
return
resourceList
;
return
resourceList
;
...
@@ -35,13 +35,13 @@ export const useResourceStore = () => {
...
@@ -35,13 +35,13 @@ export const useResourceStore = () => {
limit
,
limit
,
offset
,
offset
,
};
};
const
{
data
}
=
(
await
api
.
getResourceListWithLimit
(
resourceFind
)).
data
;
const
{
data
}
=
await
api
.
getResourceListWithLimit
(
resourceFind
)
;
const
resourceList
=
data
.
map
((
m
)
=>
convertResponseModelResource
(
m
));
const
resourceList
=
data
.
map
((
m
)
=>
convertResponseModelResource
(
m
));
store
.
dispatch
(
upsertResources
(
resourceList
));
store
.
dispatch
(
upsertResources
(
resourceList
));
return
resourceList
;
return
resourceList
;
},
},
async
createResource
(
resourceCreate
:
ResourceCreate
):
Promise
<
Resource
>
{
async
createResource
(
resourceCreate
:
ResourceCreate
):
Promise
<
Resource
>
{
const
{
data
}
=
(
await
api
.
createResource
(
resourceCreate
)).
data
;
const
{
data
}
=
await
api
.
createResource
(
resourceCreate
)
;
const
resource
=
convertResponseModelResource
(
data
);
const
resource
=
convertResponseModelResource
(
data
);
const
resourceList
=
state
.
resources
;
const
resourceList
=
state
.
resources
;
store
.
dispatch
(
setResources
([
resource
,
...
resourceList
]));
store
.
dispatch
(
setResources
([
resource
,
...
resourceList
]));
...
@@ -55,7 +55,7 @@ export const useResourceStore = () => {
...
@@ -55,7 +55,7 @@ export const useResourceStore = () => {
const
formData
=
new
FormData
();
const
formData
=
new
FormData
();
formData
.
append
(
"file"
,
file
,
filename
);
formData
.
append
(
"file"
,
file
,
filename
);
const
{
data
}
=
(
await
api
.
createResourceWithBlob
(
formData
)).
data
;
const
{
data
}
=
await
api
.
createResourceWithBlob
(
formData
)
;
const
resource
=
convertResponseModelResource
(
data
);
const
resource
=
convertResponseModelResource
(
data
);
const
resourceList
=
state
.
resources
;
const
resourceList
=
state
.
resources
;
store
.
dispatch
(
setResources
([
resource
,
...
resourceList
]));
store
.
dispatch
(
setResources
([
resource
,
...
resourceList
]));
...
@@ -71,7 +71,7 @@ export const useResourceStore = () => {
...
@@ -71,7 +71,7 @@ export const useResourceStore = () => {
const
formData
=
new
FormData
();
const
formData
=
new
FormData
();
formData
.
append
(
"file"
,
file
,
filename
);
formData
.
append
(
"file"
,
file
,
filename
);
const
{
data
}
=
(
await
api
.
createResourceWithBlob
(
formData
)).
data
;
const
{
data
}
=
await
api
.
createResourceWithBlob
(
formData
)
;
const
resource
=
convertResponseModelResource
(
data
);
const
resource
=
convertResponseModelResource
(
data
);
newResourceList
=
[
resource
,
...
newResourceList
];
newResourceList
=
[
resource
,
...
newResourceList
];
}
}
...
@@ -84,7 +84,7 @@ export const useResourceStore = () => {
...
@@ -84,7 +84,7 @@ export const useResourceStore = () => {
store
.
dispatch
(
deleteResource
(
id
));
store
.
dispatch
(
deleteResource
(
id
));
},
},
async
patchResource
(
resourcePatch
:
ResourcePatch
):
Promise
<
Resource
>
{
async
patchResource
(
resourcePatch
:
ResourcePatch
):
Promise
<
Resource
>
{
const
{
data
}
=
(
await
api
.
patchResource
(
resourcePatch
)).
data
;
const
{
data
}
=
await
api
.
patchResource
(
resourcePatch
)
;
const
resource
=
convertResponseModelResource
(
data
);
const
resource
=
convertResponseModelResource
(
data
);
store
.
dispatch
(
patchResource
(
resource
));
store
.
dispatch
(
patchResource
(
resource
));
return
resource
;
return
resource
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment