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
eefce6ad
Commit
eefce6ad
authored
Dec 23, 2023
by
Steven
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
chore: implement webhook dispatch in v2 api
parent
c6ebb555
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
296 additions
and
147 deletions
+296
-147
memo_relation_service.go
api/v2/memo_relation_service.go
+91
-0
memo_resource_service.go
api/v2/memo_resource_service.go
+66
-0
memo_service.go
api/v2/memo_service.go
+117
-133
version.go
server/version/version.go
+1
-1
index.tsx
web/src/components/MemoEditor/index.tsx
+20
-6
MemoDetail.tsx
web/src/pages/MemoDetail.tsx
+1
-7
No files found.
api/v2/memo_relation_service.go
0 → 100644
View file @
eefce6ad
package
v2
import
(
"context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
apiv2pb
"github.com/usememos/memos/proto/gen/api/v2"
"github.com/usememos/memos/store"
)
func
(
s
*
APIV2Service
)
SetMemoRelations
(
ctx
context
.
Context
,
request
*
apiv2pb
.
SetMemoRelationsRequest
)
(
*
apiv2pb
.
SetMemoRelationsResponse
,
error
)
{
referenceType
:=
store
.
MemoRelationReference
// Delete all reference relations first.
if
err
:=
s
.
Store
.
DeleteMemoRelation
(
ctx
,
&
store
.
DeleteMemoRelation
{
MemoID
:
&
request
.
Id
,
Type
:
&
referenceType
,
});
err
!=
nil
{
return
nil
,
status
.
Errorf
(
codes
.
Internal
,
"failed to delete memo relation"
)
}
for
_
,
relation
:=
range
request
.
Relations
{
if
_
,
err
:=
s
.
Store
.
UpsertMemoRelation
(
ctx
,
&
store
.
MemoRelation
{
MemoID
:
request
.
Id
,
RelatedMemoID
:
relation
.
RelatedMemoId
,
Type
:
convertMemoRelationTypeToStore
(
relation
.
Type
),
});
err
!=
nil
{
return
nil
,
status
.
Errorf
(
codes
.
Internal
,
"failed to upsert memo relation"
)
}
}
return
&
apiv2pb
.
SetMemoRelationsResponse
{},
nil
}
func
(
s
*
APIV2Service
)
ListMemoRelations
(
ctx
context
.
Context
,
request
*
apiv2pb
.
ListMemoRelationsRequest
)
(
*
apiv2pb
.
ListMemoRelationsResponse
,
error
)
{
relationList
:=
[]
*
apiv2pb
.
MemoRelation
{}
tempList
,
err
:=
s
.
Store
.
ListMemoRelations
(
ctx
,
&
store
.
FindMemoRelation
{
MemoID
:
&
request
.
Id
,
})
if
err
!=
nil
{
return
nil
,
err
}
for
_
,
relation
:=
range
tempList
{
relationList
=
append
(
relationList
,
convertMemoRelationFromStore
(
relation
))
}
tempList
,
err
=
s
.
Store
.
ListMemoRelations
(
ctx
,
&
store
.
FindMemoRelation
{
RelatedMemoID
:
&
request
.
Id
,
})
if
err
!=
nil
{
return
nil
,
err
}
for
_
,
relation
:=
range
tempList
{
relationList
=
append
(
relationList
,
convertMemoRelationFromStore
(
relation
))
}
response
:=
&
apiv2pb
.
ListMemoRelationsResponse
{
Relations
:
relationList
,
}
return
response
,
nil
}
func
convertMemoRelationFromStore
(
memoRelation
*
store
.
MemoRelation
)
*
apiv2pb
.
MemoRelation
{
return
&
apiv2pb
.
MemoRelation
{
MemoId
:
memoRelation
.
MemoID
,
RelatedMemoId
:
memoRelation
.
RelatedMemoID
,
Type
:
convertMemoRelationTypeFromStore
(
memoRelation
.
Type
),
}
}
func
convertMemoRelationTypeFromStore
(
relationType
store
.
MemoRelationType
)
apiv2pb
.
MemoRelation_Type
{
switch
relationType
{
case
store
.
MemoRelationReference
:
return
apiv2pb
.
MemoRelation_REFERENCE
case
store
.
MemoRelationComment
:
return
apiv2pb
.
MemoRelation_COMMENT
default
:
return
apiv2pb
.
MemoRelation_TYPE_UNSPECIFIED
}
}
func
convertMemoRelationTypeToStore
(
relationType
apiv2pb
.
MemoRelation_Type
)
store
.
MemoRelationType
{
switch
relationType
{
case
apiv2pb
.
MemoRelation_REFERENCE
:
return
store
.
MemoRelationReference
case
apiv2pb
.
MemoRelation_COMMENT
:
return
store
.
MemoRelationComment
default
:
return
store
.
MemoRelationReference
}
}
api/v2/memo_resource_service.go
0 → 100644
View file @
eefce6ad
package
v2
import
(
"context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
apiv2pb
"github.com/usememos/memos/proto/gen/api/v2"
"github.com/usememos/memos/store"
)
func
(
s
*
APIV2Service
)
SetMemoResources
(
ctx
context
.
Context
,
request
*
apiv2pb
.
SetMemoResourcesRequest
)
(
*
apiv2pb
.
SetMemoResourcesResponse
,
error
)
{
resources
,
err
:=
s
.
Store
.
ListResources
(
ctx
,
&
store
.
FindResource
{
MemoID
:
&
request
.
Id
})
if
err
!=
nil
{
return
nil
,
status
.
Errorf
(
codes
.
Internal
,
"failed to list resources"
)
}
// Delete resources that are not in the request.
for
_
,
resource
:=
range
resources
{
found
:=
false
for
_
,
requestResource
:=
range
request
.
Resources
{
if
resource
.
ID
==
int32
(
requestResource
.
Id
)
{
found
=
true
break
}
}
if
!
found
{
if
err
=
s
.
Store
.
DeleteResource
(
ctx
,
&
store
.
DeleteResource
{
ID
:
int32
(
resource
.
ID
),
MemoID
:
&
request
.
Id
,
});
err
!=
nil
{
return
nil
,
status
.
Errorf
(
codes
.
Internal
,
"failed to delete resource"
)
}
}
}
// Update resources' memo_id in the request.
for
_
,
resource
:=
range
request
.
Resources
{
if
_
,
err
:=
s
.
Store
.
UpdateResource
(
ctx
,
&
store
.
UpdateResource
{
ID
:
resource
.
Id
,
MemoID
:
&
request
.
Id
,
});
err
!=
nil
{
return
nil
,
status
.
Errorf
(
codes
.
Internal
,
"failed to update resource"
)
}
}
return
&
apiv2pb
.
SetMemoResourcesResponse
{},
nil
}
func
(
s
*
APIV2Service
)
ListMemoResources
(
ctx
context
.
Context
,
request
*
apiv2pb
.
ListMemoResourcesRequest
)
(
*
apiv2pb
.
ListMemoResourcesResponse
,
error
)
{
resources
,
err
:=
s
.
Store
.
ListResources
(
ctx
,
&
store
.
FindResource
{
MemoID
:
&
request
.
Id
,
})
if
err
!=
nil
{
return
nil
,
status
.
Errorf
(
codes
.
Internal
,
"failed to list resources"
)
}
response
:=
&
apiv2pb
.
ListMemoResourcesResponse
{
Resources
:
[]
*
apiv2pb
.
Resource
{},
}
for
_
,
resource
:=
range
resources
{
response
.
Resources
=
append
(
response
.
Resources
,
s
.
convertResourceFromStore
(
ctx
,
resource
))
}
return
response
,
nil
}
api/v2/memo_service.go
View file @
eefce6ad
...
@@ -8,15 +8,20 @@ import (
...
@@ -8,15 +8,20 @@ import (
"github.com/google/cel-go/cel"
"github.com/google/cel-go/cel"
"github.com/pkg/errors"
"github.com/pkg/errors"
"go.uber.org/zap"
expr
"google.golang.org/genproto/googleapis/api/expr/v1alpha1"
expr
"google.golang.org/genproto/googleapis/api/expr/v1alpha1"
"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"
apiv1
"github.com/usememos/memos/api/v1"
apiv1
"github.com/usememos/memos/api/v1"
"github.com/usememos/memos/internal/log"
"github.com/usememos/memos/plugin/gomark/parser"
"github.com/usememos/memos/plugin/gomark/parser"
"github.com/usememos/memos/plugin/gomark/parser/tokenizer"
"github.com/usememos/memos/plugin/gomark/parser/tokenizer"
"github.com/usememos/memos/plugin/webhook"
apiv2pb
"github.com/usememos/memos/proto/gen/api/v2"
apiv2pb
"github.com/usememos/memos/proto/gen/api/v2"
storepb
"github.com/usememos/memos/proto/gen/store"
"github.com/usememos/memos/server/service/metric"
"github.com/usememos/memos/store"
"github.com/usememos/memos/store"
)
)
...
@@ -38,11 +43,17 @@ func (s *APIV2Service) CreateMemo(ctx context.Context, request *apiv2pb.CreateMe
...
@@ -38,11 +43,17 @@ func (s *APIV2Service) CreateMemo(ctx context.Context, request *apiv2pb.CreateMe
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
metric
.
Enqueue
(
"memo create"
)
memoMessage
,
err
:=
s
.
convertMemoFromStore
(
ctx
,
memo
)
memoMessage
,
err
:=
s
.
convertMemoFromStore
(
ctx
,
memo
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
errors
.
Wrap
(
err
,
"failed to convert memo"
)
return
nil
,
errors
.
Wrap
(
err
,
"failed to convert memo"
)
}
}
// Try to dispatch webhook when memo is created.
if
err
:=
s
.
DispatchMemoCreatedWebhook
(
ctx
,
memoMessage
);
err
!=
nil
{
log
.
Warn
(
"Failed to dispatch memo created webhook"
,
zap
.
Error
(
err
))
}
response
:=
&
apiv2pb
.
CreateMemoResponse
{
response
:=
&
apiv2pb
.
CreateMemoResponse
{
Memo
:
memoMessage
,
Memo
:
memoMessage
,
}
}
...
@@ -222,6 +233,11 @@ func (s *APIV2Service) UpdateMemo(ctx context.Context, request *apiv2pb.UpdateMe
...
@@ -222,6 +233,11 @@ func (s *APIV2Service) UpdateMemo(ctx context.Context, request *apiv2pb.UpdateMe
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
errors
.
Wrap
(
err
,
"failed to convert memo"
)
return
nil
,
errors
.
Wrap
(
err
,
"failed to convert memo"
)
}
}
// Try to dispatch webhook when memo is updated.
if
err
:=
s
.
DispatchMemoUpdatedWebhook
(
ctx
,
memoMessage
);
err
!=
nil
{
log
.
Warn
(
"Failed to dispatch memo updated webhook"
,
zap
.
Error
(
err
))
}
return
&
apiv2pb
.
UpdateMemoResponse
{
return
&
apiv2pb
.
UpdateMemoResponse
{
Memo
:
memoMessage
,
Memo
:
memoMessage
,
},
nil
},
nil
...
@@ -252,112 +268,12 @@ func (s *APIV2Service) DeleteMemo(ctx context.Context, request *apiv2pb.DeleteMe
...
@@ -252,112 +268,12 @@ func (s *APIV2Service) DeleteMemo(ctx context.Context, request *apiv2pb.DeleteMe
return
&
apiv2pb
.
DeleteMemoResponse
{},
nil
return
&
apiv2pb
.
DeleteMemoResponse
{},
nil
}
}
func
(
s
*
APIV2Service
)
SetMemoResources
(
ctx
context
.
Context
,
request
*
apiv2pb
.
SetMemoResourcesRequest
)
(
*
apiv2pb
.
SetMemoResourcesResponse
,
error
)
{
func
(
s
*
APIV2Service
)
CreateMemoComment
(
ctx
context
.
Context
,
request
*
apiv2pb
.
CreateMemoCommentRequest
)
(
*
apiv2pb
.
CreateMemoCommentResponse
,
error
)
{
resources
,
err
:=
s
.
Store
.
ListResources
(
ctx
,
&
store
.
FindResource
{
MemoID
:
&
request
.
Id
})
relatedMemo
,
err
:=
s
.
Store
.
GetMemo
(
ctx
,
&
store
.
FindMemo
{
ID
:
&
request
.
Id
})
if
err
!=
nil
{
return
nil
,
status
.
Errorf
(
codes
.
Internal
,
"failed to list resources"
)
}
// Delete resources that are not in the request.
for
_
,
resource
:=
range
resources
{
found
:=
false
for
_
,
requestResource
:=
range
request
.
Resources
{
if
resource
.
ID
==
int32
(
requestResource
.
Id
)
{
found
=
true
break
}
}
if
!
found
{
if
err
=
s
.
Store
.
DeleteResource
(
ctx
,
&
store
.
DeleteResource
{
ID
:
int32
(
resource
.
ID
),
MemoID
:
&
request
.
Id
,
});
err
!=
nil
{
return
nil
,
status
.
Errorf
(
codes
.
Internal
,
"failed to delete resource"
)
}
}
}
// Update resources' memo_id in the request.
for
_
,
resource
:=
range
request
.
Resources
{
if
_
,
err
:=
s
.
Store
.
UpdateResource
(
ctx
,
&
store
.
UpdateResource
{
ID
:
resource
.
Id
,
MemoID
:
&
request
.
Id
,
});
err
!=
nil
{
return
nil
,
status
.
Errorf
(
codes
.
Internal
,
"failed to update resource"
)
}
}
return
&
apiv2pb
.
SetMemoResourcesResponse
{},
nil
}
func
(
s
*
APIV2Service
)
ListMemoResources
(
ctx
context
.
Context
,
request
*
apiv2pb
.
ListMemoResourcesRequest
)
(
*
apiv2pb
.
ListMemoResourcesResponse
,
error
)
{
resources
,
err
:=
s
.
Store
.
ListResources
(
ctx
,
&
store
.
FindResource
{
MemoID
:
&
request
.
Id
,
})
if
err
!=
nil
{
return
nil
,
status
.
Errorf
(
codes
.
Internal
,
"failed to list resources"
)
}
response
:=
&
apiv2pb
.
ListMemoResourcesResponse
{
Resources
:
[]
*
apiv2pb
.
Resource
{},
}
for
_
,
resource
:=
range
resources
{
response
.
Resources
=
append
(
response
.
Resources
,
s
.
convertResourceFromStore
(
ctx
,
resource
))
}
return
response
,
nil
}
func
(
s
*
APIV2Service
)
SetMemoRelations
(
ctx
context
.
Context
,
request
*
apiv2pb
.
SetMemoRelationsRequest
)
(
*
apiv2pb
.
SetMemoRelationsResponse
,
error
)
{
referenceType
:=
store
.
MemoRelationReference
// Delete all reference relations first.
if
err
:=
s
.
Store
.
DeleteMemoRelation
(
ctx
,
&
store
.
DeleteMemoRelation
{
MemoID
:
&
request
.
Id
,
Type
:
&
referenceType
,
});
err
!=
nil
{
return
nil
,
status
.
Errorf
(
codes
.
Internal
,
"failed to delete memo relation"
)
}
for
_
,
relation
:=
range
request
.
Relations
{
if
_
,
err
:=
s
.
Store
.
UpsertMemoRelation
(
ctx
,
&
store
.
MemoRelation
{
MemoID
:
request
.
Id
,
RelatedMemoID
:
relation
.
RelatedMemoId
,
Type
:
convertMemoRelationTypeToStore
(
relation
.
Type
),
});
err
!=
nil
{
return
nil
,
status
.
Errorf
(
codes
.
Internal
,
"failed to upsert memo relation"
)
}
}
return
&
apiv2pb
.
SetMemoRelationsResponse
{},
nil
}
func
(
s
*
APIV2Service
)
ListMemoRelations
(
ctx
context
.
Context
,
request
*
apiv2pb
.
ListMemoRelationsRequest
)
(
*
apiv2pb
.
ListMemoRelationsResponse
,
error
)
{
relationList
:=
[]
*
apiv2pb
.
MemoRelation
{}
tempList
,
err
:=
s
.
Store
.
ListMemoRelations
(
ctx
,
&
store
.
FindMemoRelation
{
MemoID
:
&
request
.
Id
,
})
if
err
!=
nil
{
return
nil
,
err
}
for
_
,
relation
:=
range
tempList
{
relationList
=
append
(
relationList
,
convertMemoRelationFromStore
(
relation
))
}
tempList
,
err
=
s
.
Store
.
ListMemoRelations
(
ctx
,
&
store
.
FindMemoRelation
{
RelatedMemoID
:
&
request
.
Id
,
})
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
status
.
Errorf
(
codes
.
Internal
,
"failed to get memo"
)
}
for
_
,
relation
:=
range
tempList
{
relationList
=
append
(
relationList
,
convertMemoRelationFromStore
(
relation
))
}
}
response
:=
&
apiv2pb
.
ListMemoRelationsResponse
{
Relations
:
relationList
,
}
return
response
,
nil
}
func
(
s
*
APIV2Service
)
CreateMemoComment
(
ctx
context
.
Context
,
request
*
apiv2pb
.
CreateMemoCommentRequest
)
(
*
apiv2pb
.
CreateMemoCommentResponse
,
error
)
{
// Create the comment memo first.
// Create the comment memo first.
createMemoResponse
,
err
:=
s
.
CreateMemo
(
ctx
,
request
.
Create
)
createMemoResponse
,
err
:=
s
.
CreateMemo
(
ctx
,
request
.
Create
)
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -374,6 +290,34 @@ func (s *APIV2Service) CreateMemoComment(ctx context.Context, request *apiv2pb.C
...
@@ -374,6 +290,34 @@ func (s *APIV2Service) CreateMemoComment(ctx context.Context, request *apiv2pb.C
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
status
.
Errorf
(
codes
.
Internal
,
"failed to create memo relation"
)
return
nil
,
status
.
Errorf
(
codes
.
Internal
,
"failed to create memo relation"
)
}
}
if
memo
.
Visibility
!=
apiv2pb
.
Visibility_PRIVATE
{
activity
,
err
:=
s
.
Store
.
CreateActivity
(
ctx
,
&
store
.
Activity
{
CreatorID
:
memo
.
CreatorId
,
Type
:
store
.
ActivityTypeMemoComment
,
Level
:
store
.
ActivityLevelInfo
,
Payload
:
&
storepb
.
ActivityPayload
{
MemoComment
:
&
storepb
.
ActivityMemoCommentPayload
{
MemoId
:
memo
.
Id
,
RelatedMemoId
:
request
.
Id
,
},
},
})
if
err
!=
nil
{
return
nil
,
status
.
Errorf
(
codes
.
Internal
,
"failed to create activity"
)
}
if
_
,
err
:=
s
.
Store
.
CreateInbox
(
ctx
,
&
store
.
Inbox
{
SenderID
:
memo
.
CreatorId
,
ReceiverID
:
relatedMemo
.
CreatorID
,
Status
:
store
.
UNREAD
,
Message
:
&
storepb
.
InboxMessage
{
Type
:
storepb
.
InboxMessage_TYPE_MEMO_COMMENT
,
ActivityId
:
&
activity
.
ID
,
},
});
err
!=
nil
{
return
nil
,
status
.
Errorf
(
codes
.
Internal
,
"failed to create inbox"
)
}
}
metric
.
Enqueue
(
"memo comment create"
)
response
:=
&
apiv2pb
.
CreateMemoCommentResponse
{
response
:=
&
apiv2pb
.
CreateMemoCommentResponse
{
Memo
:
memo
,
Memo
:
memo
,
...
@@ -473,36 +417,6 @@ func (s *APIV2Service) getMemoDisplayWithUpdatedTsSettingValue(ctx context.Conte
...
@@ -473,36 +417,6 @@ func (s *APIV2Service) getMemoDisplayWithUpdatedTsSettingValue(ctx context.Conte
return
memoDisplayWithUpdatedTs
,
nil
return
memoDisplayWithUpdatedTs
,
nil
}
}
func
convertMemoRelationFromStore
(
memoRelation
*
store
.
MemoRelation
)
*
apiv2pb
.
MemoRelation
{
return
&
apiv2pb
.
MemoRelation
{
MemoId
:
memoRelation
.
MemoID
,
RelatedMemoId
:
memoRelation
.
RelatedMemoID
,
Type
:
convertMemoRelationTypeFromStore
(
memoRelation
.
Type
),
}
}
func
convertMemoRelationTypeFromStore
(
relationType
store
.
MemoRelationType
)
apiv2pb
.
MemoRelation_Type
{
switch
relationType
{
case
store
.
MemoRelationReference
:
return
apiv2pb
.
MemoRelation_REFERENCE
case
store
.
MemoRelationComment
:
return
apiv2pb
.
MemoRelation_COMMENT
default
:
return
apiv2pb
.
MemoRelation_TYPE_UNSPECIFIED
}
}
func
convertMemoRelationTypeToStore
(
relationType
apiv2pb
.
MemoRelation_Type
)
store
.
MemoRelationType
{
switch
relationType
{
case
apiv2pb
.
MemoRelation_REFERENCE
:
return
store
.
MemoRelationReference
case
apiv2pb
.
MemoRelation_COMMENT
:
return
store
.
MemoRelationComment
default
:
return
store
.
MemoRelationReference
}
}
func
convertVisibilityFromStore
(
visibility
store
.
Visibility
)
apiv2pb
.
Visibility
{
func
convertVisibilityFromStore
(
visibility
store
.
Visibility
)
apiv2pb
.
Visibility
{
switch
visibility
{
switch
visibility
{
case
store
.
Private
:
case
store
.
Private
:
...
@@ -613,3 +527,73 @@ func findField(callExpr *expr.Expr_Call, filter *ListMemosFilter) {
...
@@ -613,3 +527,73 @@ func findField(callExpr *expr.Expr_Call, filter *ListMemosFilter) {
}
}
}
}
}
}
// DispatchMemoCreatedWebhook dispatches webhook when memo is created.
func
(
s
*
APIV2Service
)
DispatchMemoCreatedWebhook
(
ctx
context
.
Context
,
memo
*
apiv2pb
.
Memo
)
error
{
return
s
.
dispatchMemoRelatedWebhook
(
ctx
,
memo
,
"memos.memo.created"
)
}
// DispatchMemoUpdatedWebhook dispatches webhook when memo is updated.
func
(
s
*
APIV2Service
)
DispatchMemoUpdatedWebhook
(
ctx
context
.
Context
,
memo
*
apiv2pb
.
Memo
)
error
{
return
s
.
dispatchMemoRelatedWebhook
(
ctx
,
memo
,
"memos.memo.updated"
)
}
func
(
s
*
APIV2Service
)
dispatchMemoRelatedWebhook
(
ctx
context
.
Context
,
memo
*
apiv2pb
.
Memo
,
activityType
string
)
error
{
webhooks
,
err
:=
s
.
Store
.
ListWebhooks
(
ctx
,
&
store
.
FindWebhook
{
CreatorID
:
&
memo
.
CreatorId
,
})
if
err
!=
nil
{
return
err
}
metric
.
Enqueue
(
"webhook dispatch"
)
for
_
,
hook
:=
range
webhooks
{
payload
:=
convertMemoToWebhookPayload
(
memo
)
payload
.
ActivityType
=
activityType
payload
.
URL
=
hook
.
Url
err
:=
webhook
.
Post
(
*
payload
)
if
err
!=
nil
{
return
errors
.
Wrap
(
err
,
"failed to post webhook"
)
}
}
return
nil
}
func
convertMemoToWebhookPayload
(
memo
*
apiv2pb
.
Memo
)
*
webhook
.
WebhookPayload
{
return
&
webhook
.
WebhookPayload
{
CreatorID
:
memo
.
CreatorId
,
CreatedTs
:
time
.
Now
()
.
Unix
(),
Memo
:
&
webhook
.
Memo
{
ID
:
memo
.
Id
,
CreatorID
:
memo
.
CreatorId
,
CreatedTs
:
memo
.
CreateTime
.
Seconds
,
UpdatedTs
:
memo
.
UpdateTime
.
Seconds
,
Content
:
memo
.
Content
,
Visibility
:
memo
.
Visibility
.
String
(),
Pinned
:
memo
.
Pinned
,
ResourceList
:
func
()
[]
*
webhook
.
Resource
{
resources
:=
[]
*
webhook
.
Resource
{}
for
_
,
resource
:=
range
memo
.
Resources
{
resources
=
append
(
resources
,
&
webhook
.
Resource
{
ID
:
resource
.
Id
,
Filename
:
resource
.
Filename
,
ExternalLink
:
resource
.
ExternalLink
,
Type
:
resource
.
Type
,
Size
:
resource
.
Size
,
})
}
return
resources
}(),
RelationList
:
func
()
[]
*
webhook
.
MemoRelation
{
relations
:=
[]
*
webhook
.
MemoRelation
{}
for
_
,
relation
:=
range
memo
.
Relations
{
relations
=
append
(
relations
,
&
webhook
.
MemoRelation
{
MemoID
:
relation
.
MemoId
,
RelatedMemoID
:
relation
.
RelatedMemoId
,
Type
:
relation
.
Type
.
String
(),
})
}
return
relations
}(),
},
}
}
server/version/version.go
View file @
eefce6ad
...
@@ -12,7 +12,7 @@ import (
...
@@ -12,7 +12,7 @@ import (
var
Version
=
"0.18.1"
var
Version
=
"0.18.1"
// DevVersion is the service current development version.
// DevVersion is the service current development version.
var
DevVersion
=
"0.18.
1
"
var
DevVersion
=
"0.18.
2
"
func
GetCurrentVersion
(
mode
string
)
string
{
func
GetCurrentVersion
(
mode
string
)
string
{
if
mode
==
"dev"
||
mode
==
"demo"
{
if
mode
==
"dev"
||
mode
==
"demo"
{
...
...
web/src/components/MemoEditor/index.tsx
View file @
eefce6ad
...
@@ -9,7 +9,7 @@ import { TAB_SPACE_WIDTH, UNKNOWN_ID } from "@/helpers/consts";
...
@@ -9,7 +9,7 @@ import { TAB_SPACE_WIDTH, UNKNOWN_ID } from "@/helpers/consts";
import
{
useGlobalStore
,
useResourceStore
}
from
"@/store/module"
;
import
{
useGlobalStore
,
useResourceStore
}
from
"@/store/module"
;
import
{
useMemoStore
,
useUserStore
}
from
"@/store/v1"
;
import
{
useMemoStore
,
useUserStore
}
from
"@/store/v1"
;
import
{
MemoRelation
,
MemoRelation_Type
}
from
"@/types/proto/api/v2/memo_relation_service"
;
import
{
MemoRelation
,
MemoRelation_Type
}
from
"@/types/proto/api/v2/memo_relation_service"
;
import
{
Visibility
}
from
"@/types/proto/api/v2/memo_service"
;
import
{
Memo
,
Visibility
}
from
"@/types/proto/api/v2/memo_service"
;
import
{
Resource
}
from
"@/types/proto/api/v2/resource_service"
;
import
{
Resource
}
from
"@/types/proto/api/v2/resource_service"
;
import
{
UserSetting
}
from
"@/types/proto/api/v2/user_service"
;
import
{
UserSetting
}
from
"@/types/proto/api/v2/user_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
...
@@ -28,6 +28,7 @@ interface Props {
...
@@ -28,6 +28,7 @@ interface Props {
editorClassName
?:
string
;
editorClassName
?:
string
;
cacheKey
?:
string
;
cacheKey
?:
string
;
memoId
?:
number
;
memoId
?:
number
;
parentMemoId
?:
number
;
relationList
?:
MemoRelation
[];
relationList
?:
MemoRelation
[];
onConfirm
?:
(
memoId
:
number
)
=>
void
;
onConfirm
?:
(
memoId
:
number
)
=>
void
;
}
}
...
@@ -41,7 +42,7 @@ interface State {
...
@@ -41,7 +42,7 @@ interface State {
}
}
const
MemoEditor
=
(
props
:
Props
)
=>
{
const
MemoEditor
=
(
props
:
Props
)
=>
{
const
{
className
,
editorClassName
,
cacheKey
,
memoId
,
onConfirm
}
=
props
;
const
{
className
,
editorClassName
,
cacheKey
,
memoId
,
parentMemoId
,
onConfirm
}
=
props
;
const
{
i18n
}
=
useTranslation
();
const
{
i18n
}
=
useTranslation
();
const
t
=
useTranslate
();
const
t
=
useTranslate
();
const
contentCacheKey
=
`memo-editor-
${
cacheKey
}
`
;
const
contentCacheKey
=
`memo-editor-
${
cacheKey
}
`
;
...
@@ -260,6 +261,7 @@ const MemoEditor = (props: Props) => {
...
@@ -260,6 +261,7 @@ const MemoEditor = (props: Props) => {
});
});
const
content
=
editorRef
.
current
?.
getContent
()
??
""
;
const
content
=
editorRef
.
current
?.
getContent
()
??
""
;
try
{
try
{
// Update memo.
if
(
memoId
&&
memoId
!==
UNKNOWN_ID
)
{
if
(
memoId
&&
memoId
!==
UNKNOWN_ID
)
{
const
prevMemo
=
await
memoStore
.
getOrFetchMemoById
(
memoId
??
UNKNOWN_ID
);
const
prevMemo
=
await
memoStore
.
getOrFetchMemoById
(
memoId
??
UNKNOWN_ID
);
if
(
prevMemo
)
{
if
(
prevMemo
)
{
...
@@ -284,10 +286,22 @@ const MemoEditor = (props: Props) => {
...
@@ -284,10 +286,22 @@ const MemoEditor = (props: Props) => {
}
}
}
}
}
else
{
}
else
{
const
memo
=
await
memoStore
.
createMemo
({
// Create memo or memo comment.
content
,
const
request
=
!
parentMemoId
visibility
:
state
.
memoVisibility
,
?
memoStore
.
createMemo
({
});
content
,
visibility
:
state
.
memoVisibility
,
})
:
memoServiceClient
.
createMemoComment
({
id
:
parentMemoId
,
create
:
{
content
,
visibility
:
state
.
memoVisibility
,
},
})
.
then
(({
memo
})
=>
memo
as
Memo
);
const
memo
=
await
request
;
await
memoServiceClient
.
setMemoResources
({
await
memoServiceClient
.
setMemoResources
({
id
:
memo
.
id
,
id
:
memo
.
id
,
resources
:
state
.
resourceList
,
resources
:
state
.
resourceList
,
...
...
web/src/pages/MemoDetail.tsx
View file @
eefce6ad
...
@@ -15,7 +15,6 @@ import MobileHeader from "@/components/MobileHeader";
...
@@ -15,7 +15,6 @@ import MobileHeader from "@/components/MobileHeader";
import
showShareMemoDialog
from
"@/components/ShareMemoDialog"
;
import
showShareMemoDialog
from
"@/components/ShareMemoDialog"
;
import
UserAvatar
from
"@/components/UserAvatar"
;
import
UserAvatar
from
"@/components/UserAvatar"
;
import
VisibilityIcon
from
"@/components/VisibilityIcon"
;
import
VisibilityIcon
from
"@/components/VisibilityIcon"
;
import
{
UNKNOWN_ID
}
from
"@/helpers/consts"
;
import
{
getDateTimeString
}
from
"@/helpers/datetime"
;
import
{
getDateTimeString
}
from
"@/helpers/datetime"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useNavigateTo
from
"@/hooks/useNavigateTo"
;
import
useNavigateTo
from
"@/hooks/useNavigateTo"
;
...
@@ -214,12 +213,7 @@ const MemoDetail = () => {
...
@@ -214,12 +213,7 @@ const MemoDetail = () => {
{
/* Only show comment editor when user login */
}
{
/* Only show comment editor when user login */
}
{
currentUser
&&
(
{
currentUser
&&
(
<
MemoEditor
<
MemoEditor
key=
{
memo
.
id
}
cacheKey=
{
`comment-editor-${memo.id}`
}
parentMemoId=
{
memo
.
id
}
onConfirm=
{
handleCommentCreated
}
/>
key=
{
memo
.
id
}
cacheKey=
{
`comment-editor-${memo.id}`
}
relationList=
{
[{
memoId
:
UNKNOWN_ID
,
relatedMemoId
:
memo
.
id
,
type
:
MemoRelation_Type
.
COMMENT
}]
}
onConfirm=
{
handleCommentCreated
}
/>
)
}
)
}
</
div
>
</
div
>
</
div
>
</
div
>
...
...
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