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
3220adbf
Commit
3220adbf
authored
Dec 26, 2024
by
johnnyjoy
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactor: split memo service
parent
a78bfffb
Changes
4
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
420 additions
and
393 deletions
+420
-393
common.go
server/router/api/v1/common.go
+9
-0
memo_service.go
server/router/api/v1/memo_service.go
+0
-393
memo_service_converter.go
server/router/api/v1/memo_service_converter.go
+145
-0
memo_service_filter.go
server/router/api/v1/memo_service_filter.go
+266
-0
No files found.
server/router/api/v1/common.go
View file @
3220adbf
...
@@ -10,6 +10,11 @@ import (
...
@@ -10,6 +10,11 @@ import (
"github.com/usememos/memos/store"
"github.com/usememos/memos/store"
)
)
const
(
// DefaultPageSize is the default page size for requests.
DefaultPageSize
=
10
)
func
convertRowStatusFromStore
(
rowStatus
store
.
RowStatus
)
v1pb
.
RowStatus
{
func
convertRowStatusFromStore
(
rowStatus
store
.
RowStatus
)
v1pb
.
RowStatus
{
switch
rowStatus
{
switch
rowStatus
{
case
store
.
Normal
:
case
store
.
Normal
:
...
@@ -57,3 +62,7 @@ func unmarshalPageToken(s string, pageToken *v1pb.PageToken) error {
...
@@ -57,3 +62,7 @@ func unmarshalPageToken(s string, pageToken *v1pb.PageToken) error {
}
}
return
nil
return
nil
}
}
func
isSuperUser
(
user
*
store
.
User
)
bool
{
return
user
.
Role
==
store
.
RoleAdmin
||
user
.
Role
==
store
.
RoleHost
}
server/router/api/v1/memo_service.go
View file @
3220adbf
This diff is collapsed.
Click to expand it.
server/router/api/v1/memo_service_converter.go
0 → 100644
View file @
3220adbf
package
v1
import
(
"context"
"fmt"
"time"
"github.com/pkg/errors"
"google.golang.org/protobuf/types/known/timestamppb"
"github.com/usememos/gomark/parser"
"github.com/usememos/gomark/parser/tokenizer"
v1pb
"github.com/usememos/memos/proto/gen/api/v1"
storepb
"github.com/usememos/memos/proto/gen/store"
"github.com/usememos/memos/store"
)
func
(
s
*
APIV1Service
)
convertMemoFromStore
(
ctx
context
.
Context
,
memo
*
store
.
Memo
,
view
v1pb
.
MemoView
)
(
*
v1pb
.
Memo
,
error
)
{
displayTs
:=
memo
.
CreatedTs
workspaceMemoRelatedSetting
,
err
:=
s
.
Store
.
GetWorkspaceMemoRelatedSetting
(
ctx
)
if
err
!=
nil
{
return
nil
,
errors
.
Wrap
(
err
,
"failed to get workspace memo related setting"
)
}
if
workspaceMemoRelatedSetting
.
DisplayWithUpdateTime
{
displayTs
=
memo
.
UpdatedTs
}
name
:=
fmt
.
Sprintf
(
"%s%d"
,
MemoNamePrefix
,
memo
.
ID
)
memoMessage
:=
&
v1pb
.
Memo
{
Name
:
name
,
Uid
:
memo
.
UID
,
RowStatus
:
convertRowStatusFromStore
(
memo
.
RowStatus
),
Creator
:
fmt
.
Sprintf
(
"%s%d"
,
UserNamePrefix
,
memo
.
CreatorID
),
CreateTime
:
timestamppb
.
New
(
time
.
Unix
(
memo
.
CreatedTs
,
0
)),
UpdateTime
:
timestamppb
.
New
(
time
.
Unix
(
memo
.
UpdatedTs
,
0
)),
DisplayTime
:
timestamppb
.
New
(
time
.
Unix
(
displayTs
,
0
)),
Content
:
memo
.
Content
,
Visibility
:
convertVisibilityFromStore
(
memo
.
Visibility
),
Pinned
:
memo
.
Pinned
,
Tags
:
memo
.
Payload
.
Tags
,
}
if
memo
.
Payload
!=
nil
{
memoMessage
.
Property
=
convertMemoPropertyFromStore
(
memo
.
Payload
.
Property
)
memoMessage
.
Location
=
convertLocationFromStore
(
memo
.
Payload
.
Location
)
}
if
memo
.
ParentID
!=
nil
{
parent
:=
fmt
.
Sprintf
(
"%s%d"
,
MemoNamePrefix
,
*
memo
.
ParentID
)
memoMessage
.
Parent
=
&
parent
}
// Fill content when view is MEMO_VIEW_FULL.
if
view
==
v1pb
.
MemoView_MEMO_VIEW_FULL
{
listMemoRelationsResponse
,
err
:=
s
.
ListMemoRelations
(
ctx
,
&
v1pb
.
ListMemoRelationsRequest
{
Name
:
name
})
if
err
!=
nil
{
return
nil
,
errors
.
Wrap
(
err
,
"failed to list memo relations"
)
}
memoMessage
.
Relations
=
listMemoRelationsResponse
.
Relations
listMemoResourcesResponse
,
err
:=
s
.
ListMemoResources
(
ctx
,
&
v1pb
.
ListMemoResourcesRequest
{
Name
:
name
})
if
err
!=
nil
{
return
nil
,
errors
.
Wrap
(
err
,
"failed to list memo resources"
)
}
memoMessage
.
Resources
=
listMemoResourcesResponse
.
Resources
listMemoReactionsResponse
,
err
:=
s
.
ListMemoReactions
(
ctx
,
&
v1pb
.
ListMemoReactionsRequest
{
Name
:
name
})
if
err
!=
nil
{
return
nil
,
errors
.
Wrap
(
err
,
"failed to list memo reactions"
)
}
memoMessage
.
Reactions
=
listMemoReactionsResponse
.
Reactions
nodes
,
err
:=
parser
.
Parse
(
tokenizer
.
Tokenize
(
memo
.
Content
))
if
err
!=
nil
{
return
nil
,
errors
.
Wrap
(
err
,
"failed to parse content"
)
}
memoMessage
.
Nodes
=
convertFromASTNodes
(
nodes
)
snippet
,
err
:=
getMemoContentSnippet
(
memo
.
Content
)
if
err
!=
nil
{
return
nil
,
errors
.
Wrap
(
err
,
"failed to get memo content snippet"
)
}
memoMessage
.
Snippet
=
snippet
}
return
memoMessage
,
nil
}
func
convertMemoPropertyFromStore
(
property
*
storepb
.
MemoPayload_Property
)
*
v1pb
.
MemoProperty
{
if
property
==
nil
{
return
nil
}
return
&
v1pb
.
MemoProperty
{
HasLink
:
property
.
HasLink
,
HasTaskList
:
property
.
HasTaskList
,
HasCode
:
property
.
HasCode
,
HasIncompleteTasks
:
property
.
HasIncompleteTasks
,
}
}
func
convertLocationFromStore
(
location
*
storepb
.
MemoPayload_Location
)
*
v1pb
.
Location
{
if
location
==
nil
{
return
nil
}
return
&
v1pb
.
Location
{
Placeholder
:
location
.
Placeholder
,
Latitude
:
location
.
Latitude
,
Longitude
:
location
.
Longitude
,
}
}
func
convertLocationToStore
(
location
*
v1pb
.
Location
)
*
storepb
.
MemoPayload_Location
{
if
location
==
nil
{
return
nil
}
return
&
storepb
.
MemoPayload_Location
{
Placeholder
:
location
.
Placeholder
,
Latitude
:
location
.
Latitude
,
Longitude
:
location
.
Longitude
,
}
}
func
convertVisibilityFromStore
(
visibility
store
.
Visibility
)
v1pb
.
Visibility
{
switch
visibility
{
case
store
.
Private
:
return
v1pb
.
Visibility_PRIVATE
case
store
.
Protected
:
return
v1pb
.
Visibility_PROTECTED
case
store
.
Public
:
return
v1pb
.
Visibility_PUBLIC
default
:
return
v1pb
.
Visibility_VISIBILITY_UNSPECIFIED
}
}
func
convertVisibilityToStore
(
visibility
v1pb
.
Visibility
)
store
.
Visibility
{
switch
visibility
{
case
v1pb
.
Visibility_PRIVATE
:
return
store
.
Private
case
v1pb
.
Visibility_PROTECTED
:
return
store
.
Protected
case
v1pb
.
Visibility_PUBLIC
:
return
store
.
Public
default
:
return
store
.
Private
}
}
server/router/api/v1/memo_service_filter.go
0 → 100644
View file @
3220adbf
package
v1
import
(
"context"
"github.com/google/cel-go/cel"
"github.com/pkg/errors"
expr
"google.golang.org/genproto/googleapis/api/expr/v1alpha1"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"github.com/usememos/memos/store"
)
func
(
s
*
APIV1Service
)
buildMemoFindWithFilter
(
ctx
context
.
Context
,
find
*
store
.
FindMemo
,
filter
string
)
error
{
if
find
.
PayloadFind
==
nil
{
find
.
PayloadFind
=
&
store
.
FindMemoPayload
{}
}
if
filter
!=
""
{
filter
,
err
:=
parseMemoFilter
(
filter
)
if
err
!=
nil
{
return
status
.
Errorf
(
codes
.
InvalidArgument
,
"invalid filter: %v"
,
err
)
}
if
len
(
filter
.
ContentSearch
)
>
0
{
find
.
ContentSearch
=
filter
.
ContentSearch
}
if
len
(
filter
.
Visibilities
)
>
0
{
find
.
VisibilityList
=
filter
.
Visibilities
}
if
filter
.
TagSearch
!=
nil
{
if
find
.
PayloadFind
==
nil
{
find
.
PayloadFind
=
&
store
.
FindMemoPayload
{}
}
find
.
PayloadFind
.
TagSearch
=
filter
.
TagSearch
}
if
filter
.
OrderByPinned
{
find
.
OrderByPinned
=
filter
.
OrderByPinned
}
if
filter
.
OrderByTimeAsc
{
find
.
OrderByTimeAsc
=
filter
.
OrderByTimeAsc
}
if
filter
.
DisplayTimeAfter
!=
nil
{
workspaceMemoRelatedSetting
,
err
:=
s
.
Store
.
GetWorkspaceMemoRelatedSetting
(
ctx
)
if
err
!=
nil
{
return
status
.
Errorf
(
codes
.
Internal
,
"failed to get workspace memo related setting"
)
}
if
workspaceMemoRelatedSetting
.
DisplayWithUpdateTime
{
find
.
UpdatedTsAfter
=
filter
.
DisplayTimeAfter
}
else
{
find
.
CreatedTsAfter
=
filter
.
DisplayTimeAfter
}
}
if
filter
.
DisplayTimeBefore
!=
nil
{
workspaceMemoRelatedSetting
,
err
:=
s
.
Store
.
GetWorkspaceMemoRelatedSetting
(
ctx
)
if
err
!=
nil
{
return
status
.
Errorf
(
codes
.
Internal
,
"failed to get workspace memo related setting"
)
}
if
workspaceMemoRelatedSetting
.
DisplayWithUpdateTime
{
find
.
UpdatedTsBefore
=
filter
.
DisplayTimeBefore
}
else
{
find
.
CreatedTsBefore
=
filter
.
DisplayTimeBefore
}
}
if
filter
.
Creator
!=
nil
{
userID
,
err
:=
ExtractUserIDFromName
(
*
filter
.
Creator
)
if
err
!=
nil
{
return
errors
.
Wrap
(
err
,
"invalid user name"
)
}
user
,
err
:=
s
.
Store
.
GetUser
(
ctx
,
&
store
.
FindUser
{
ID
:
&
userID
,
})
if
err
!=
nil
{
return
status
.
Errorf
(
codes
.
Internal
,
"failed to get user"
)
}
if
user
==
nil
{
return
status
.
Errorf
(
codes
.
NotFound
,
"user not found"
)
}
find
.
CreatorID
=
&
user
.
ID
}
if
filter
.
RowStatus
!=
nil
{
find
.
RowStatus
=
filter
.
RowStatus
}
if
filter
.
Random
{
find
.
Random
=
filter
.
Random
}
if
filter
.
Limit
!=
nil
{
find
.
Limit
=
filter
.
Limit
}
if
filter
.
IncludeComments
{
find
.
ExcludeComments
=
false
}
if
filter
.
HasLink
{
find
.
PayloadFind
.
HasLink
=
true
}
if
filter
.
HasTaskList
{
find
.
PayloadFind
.
HasTaskList
=
true
}
if
filter
.
HasCode
{
find
.
PayloadFind
.
HasCode
=
true
}
if
filter
.
HasIncompleteTasks
{
find
.
PayloadFind
.
HasIncompleteTasks
=
true
}
}
user
,
err
:=
s
.
GetCurrentUser
(
ctx
)
if
err
!=
nil
{
return
status
.
Errorf
(
codes
.
Internal
,
"failed to get current user"
)
}
// If the user is not authenticated, only public memos are visible.
if
user
==
nil
{
if
filter
==
""
{
// If no filter is provided, return an error.
return
status
.
Errorf
(
codes
.
InvalidArgument
,
"filter is required for unauthenticated user"
)
}
find
.
VisibilityList
=
[]
store
.
Visibility
{
store
.
Public
}
}
else
if
find
.
CreatorID
==
nil
||
*
find
.
CreatorID
!=
user
.
ID
{
// If creator is not specified or the creator is not the current user, only public and protected memos are visible.
find
.
VisibilityList
=
[]
store
.
Visibility
{
store
.
Public
,
store
.
Protected
}
}
workspaceMemoRelatedSetting
,
err
:=
s
.
Store
.
GetWorkspaceMemoRelatedSetting
(
ctx
)
if
err
!=
nil
{
return
status
.
Errorf
(
codes
.
Internal
,
"failed to get workspace memo related setting"
)
}
if
workspaceMemoRelatedSetting
.
DisplayWithUpdateTime
{
find
.
OrderByUpdatedTs
=
true
}
return
nil
}
// MemoFilterCELAttributes are the CEL attributes.
var
MemoFilterCELAttributes
=
[]
cel
.
EnvOption
{
cel
.
Variable
(
"content_search"
,
cel
.
ListType
(
cel
.
StringType
)),
cel
.
Variable
(
"visibilities"
,
cel
.
ListType
(
cel
.
StringType
)),
cel
.
Variable
(
"tag_search"
,
cel
.
ListType
(
cel
.
StringType
)),
cel
.
Variable
(
"order_by_pinned"
,
cel
.
BoolType
),
cel
.
Variable
(
"order_by_time_asc"
,
cel
.
BoolType
),
cel
.
Variable
(
"display_time_before"
,
cel
.
IntType
),
cel
.
Variable
(
"display_time_after"
,
cel
.
IntType
),
cel
.
Variable
(
"creator"
,
cel
.
StringType
),
cel
.
Variable
(
"uid"
,
cel
.
StringType
),
cel
.
Variable
(
"row_status"
,
cel
.
StringType
),
cel
.
Variable
(
"random"
,
cel
.
BoolType
),
cel
.
Variable
(
"limit"
,
cel
.
IntType
),
cel
.
Variable
(
"include_comments"
,
cel
.
BoolType
),
cel
.
Variable
(
"has_link"
,
cel
.
BoolType
),
cel
.
Variable
(
"has_task_list"
,
cel
.
BoolType
),
cel
.
Variable
(
"has_code"
,
cel
.
BoolType
),
cel
.
Variable
(
"has_incomplete_tasks"
,
cel
.
BoolType
),
}
type
MemoFilter
struct
{
ContentSearch
[]
string
Visibilities
[]
store
.
Visibility
TagSearch
[]
string
OrderByPinned
bool
OrderByTimeAsc
bool
DisplayTimeBefore
*
int64
DisplayTimeAfter
*
int64
Creator
*
string
RowStatus
*
store
.
RowStatus
Random
bool
Limit
*
int
IncludeComments
bool
HasLink
bool
HasTaskList
bool
HasCode
bool
HasIncompleteTasks
bool
}
func
parseMemoFilter
(
expression
string
)
(
*
MemoFilter
,
error
)
{
e
,
err
:=
cel
.
NewEnv
(
MemoFilterCELAttributes
...
)
if
err
!=
nil
{
return
nil
,
err
}
ast
,
issues
:=
e
.
Compile
(
expression
)
if
issues
!=
nil
{
return
nil
,
errors
.
Errorf
(
"found issue %v"
,
issues
)
}
filter
:=
&
MemoFilter
{}
expr
,
err
:=
cel
.
AstToParsedExpr
(
ast
)
if
err
!=
nil
{
return
nil
,
err
}
callExpr
:=
expr
.
GetExpr
()
.
GetCallExpr
()
findMemoField
(
callExpr
,
filter
)
return
filter
,
nil
}
func
findMemoField
(
callExpr
*
expr
.
Expr_Call
,
filter
*
MemoFilter
)
{
if
len
(
callExpr
.
Args
)
==
2
{
idExpr
:=
callExpr
.
Args
[
0
]
.
GetIdentExpr
()
if
idExpr
!=
nil
{
if
idExpr
.
Name
==
"content_search"
{
contentSearch
:=
[]
string
{}
for
_
,
expr
:=
range
callExpr
.
Args
[
1
]
.
GetListExpr
()
.
GetElements
()
{
value
:=
expr
.
GetConstExpr
()
.
GetStringValue
()
contentSearch
=
append
(
contentSearch
,
value
)
}
filter
.
ContentSearch
=
contentSearch
}
else
if
idExpr
.
Name
==
"visibilities"
{
visibilities
:=
[]
store
.
Visibility
{}
for
_
,
expr
:=
range
callExpr
.
Args
[
1
]
.
GetListExpr
()
.
GetElements
()
{
value
:=
expr
.
GetConstExpr
()
.
GetStringValue
()
visibilities
=
append
(
visibilities
,
store
.
Visibility
(
value
))
}
filter
.
Visibilities
=
visibilities
}
else
if
idExpr
.
Name
==
"tag_search"
{
tagSearch
:=
[]
string
{}
for
_
,
expr
:=
range
callExpr
.
Args
[
1
]
.
GetListExpr
()
.
GetElements
()
{
value
:=
expr
.
GetConstExpr
()
.
GetStringValue
()
tagSearch
=
append
(
tagSearch
,
value
)
}
filter
.
TagSearch
=
tagSearch
}
else
if
idExpr
.
Name
==
"order_by_pinned"
{
value
:=
callExpr
.
Args
[
1
]
.
GetConstExpr
()
.
GetBoolValue
()
filter
.
OrderByPinned
=
value
}
else
if
idExpr
.
Name
==
"order_by_time_asc"
{
value
:=
callExpr
.
Args
[
1
]
.
GetConstExpr
()
.
GetBoolValue
()
filter
.
OrderByTimeAsc
=
value
}
else
if
idExpr
.
Name
==
"display_time_before"
{
displayTimeBefore
:=
callExpr
.
Args
[
1
]
.
GetConstExpr
()
.
GetInt64Value
()
filter
.
DisplayTimeBefore
=
&
displayTimeBefore
}
else
if
idExpr
.
Name
==
"display_time_after"
{
displayTimeAfter
:=
callExpr
.
Args
[
1
]
.
GetConstExpr
()
.
GetInt64Value
()
filter
.
DisplayTimeAfter
=
&
displayTimeAfter
}
else
if
idExpr
.
Name
==
"creator"
{
creator
:=
callExpr
.
Args
[
1
]
.
GetConstExpr
()
.
GetStringValue
()
filter
.
Creator
=
&
creator
}
else
if
idExpr
.
Name
==
"row_status"
{
rowStatus
:=
store
.
RowStatus
(
callExpr
.
Args
[
1
]
.
GetConstExpr
()
.
GetStringValue
())
filter
.
RowStatus
=
&
rowStatus
}
else
if
idExpr
.
Name
==
"random"
{
value
:=
callExpr
.
Args
[
1
]
.
GetConstExpr
()
.
GetBoolValue
()
filter
.
Random
=
value
}
else
if
idExpr
.
Name
==
"limit"
{
limit
:=
int
(
callExpr
.
Args
[
1
]
.
GetConstExpr
()
.
GetInt64Value
())
filter
.
Limit
=
&
limit
}
else
if
idExpr
.
Name
==
"include_comments"
{
value
:=
callExpr
.
Args
[
1
]
.
GetConstExpr
()
.
GetBoolValue
()
filter
.
IncludeComments
=
value
}
else
if
idExpr
.
Name
==
"has_link"
{
value
:=
callExpr
.
Args
[
1
]
.
GetConstExpr
()
.
GetBoolValue
()
filter
.
HasLink
=
value
}
else
if
idExpr
.
Name
==
"has_task_list"
{
value
:=
callExpr
.
Args
[
1
]
.
GetConstExpr
()
.
GetBoolValue
()
filter
.
HasTaskList
=
value
}
else
if
idExpr
.
Name
==
"has_code"
{
value
:=
callExpr
.
Args
[
1
]
.
GetConstExpr
()
.
GetBoolValue
()
filter
.
HasCode
=
value
}
else
if
idExpr
.
Name
==
"has_incomplete_tasks"
{
value
:=
callExpr
.
Args
[
1
]
.
GetConstExpr
()
.
GetBoolValue
()
filter
.
HasIncompleteTasks
=
value
}
return
}
}
for
_
,
arg
:=
range
callExpr
.
Args
{
callExpr
:=
arg
.
GetCallExpr
()
if
callExpr
!=
nil
{
findMemoField
(
callExpr
,
filter
)
}
}
}
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