Commit db95b94c authored by Steven's avatar Steven

chore: implement webhook service

parent 1a5bce49
...@@ -24,6 +24,7 @@ type APIV2Service struct { ...@@ -24,6 +24,7 @@ type APIV2Service struct {
apiv2pb.UnimplementedTagServiceServer apiv2pb.UnimplementedTagServiceServer
apiv2pb.UnimplementedInboxServiceServer apiv2pb.UnimplementedInboxServiceServer
apiv2pb.UnimplementedActivityServiceServer apiv2pb.UnimplementedActivityServiceServer
apiv2pb.UnimplementedWebhookServiceServer
Secret string Secret string
Profile *profile.Profile Profile *profile.Profile
...@@ -56,6 +57,7 @@ func NewAPIV2Service(secret string, profile *profile.Profile, store *store.Store ...@@ -56,6 +57,7 @@ func NewAPIV2Service(secret string, profile *profile.Profile, store *store.Store
apiv2pb.RegisterResourceServiceServer(grpcServer, apiv2Service) apiv2pb.RegisterResourceServiceServer(grpcServer, apiv2Service)
apiv2pb.RegisterInboxServiceServer(grpcServer, apiv2Service) apiv2pb.RegisterInboxServiceServer(grpcServer, apiv2Service)
apiv2pb.RegisterActivityServiceServer(grpcServer, apiv2Service) apiv2pb.RegisterActivityServiceServer(grpcServer, apiv2Service)
apiv2pb.RegisterWebhookServiceServer(grpcServer, apiv2Service)
reflection.Register(grpcServer) reflection.Register(grpcServer)
return apiv2Service return apiv2Service
...@@ -100,6 +102,9 @@ func (s *APIV2Service) RegisterGateway(ctx context.Context, e *echo.Echo) error ...@@ -100,6 +102,9 @@ func (s *APIV2Service) RegisterGateway(ctx context.Context, e *echo.Echo) error
if err := apiv2pb.RegisterActivityServiceHandler(context.Background(), gwMux, conn); err != nil { if err := apiv2pb.RegisterActivityServiceHandler(context.Background(), gwMux, conn); err != nil {
return err return err
} }
if err := apiv2pb.RegisterWebhookServiceHandler(context.Background(), gwMux, conn); err != nil {
return err
}
e.Any("/api/v2/*", echo.WrapHandler(gwMux)) e.Any("/api/v2/*", echo.WrapHandler(gwMux))
// GRPC web proxy. // GRPC web proxy.
......
package v2
import (
"context"
"time"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/timestamppb"
apiv2pb "github.com/usememos/memos/proto/gen/api/v2"
storepb "github.com/usememos/memos/proto/gen/store"
"github.com/usememos/memos/store"
)
func (s *APIV2Service) CreateWebhook(ctx context.Context, request *apiv2pb.CreateWebhookRequest) (*apiv2pb.CreateWebhookResponse, error) {
currentUser, err := getCurrentUser(ctx, s.Store)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get user: %v", err)
}
webhook, err := s.Store.CreateWebhook(ctx, &storepb.Webhook{
CreatorId: currentUser.ID,
Name: request.Name,
Url: request.Url,
})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to create webhook, error: %+v", err)
}
return &apiv2pb.CreateWebhookResponse{
Webhook: convertWebhookFromStore(webhook),
}, nil
}
func (s *APIV2Service) ListWebhooks(ctx context.Context, request *apiv2pb.ListWebhooksRequest) (*apiv2pb.ListWebhooksResponse, error) {
webhooks, err := s.Store.ListWebhooks(ctx, &store.FindWebhook{
CreatorID: &request.CreatorId,
})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to list webhooks, error: %+v", err)
}
response := &apiv2pb.ListWebhooksResponse{
Webhooks: []*apiv2pb.Webhook{},
}
for _, webhook := range webhooks {
response.Webhooks = append(response.Webhooks, convertWebhookFromStore(webhook))
}
return response, nil
}
func (s *APIV2Service) GetWebhook(ctx context.Context, request *apiv2pb.GetWebhookRequest) (*apiv2pb.GetWebhookResponse, error) {
currentUser, err := getCurrentUser(ctx, s.Store)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get user: %v", err)
}
webhook, err := s.Store.GetWebhooks(ctx, &store.FindWebhook{
ID: &request.Id,
CreatorID: &currentUser.ID,
})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get webhook, error: %+v", err)
}
if webhook == nil {
return nil, status.Errorf(codes.NotFound, "webhook not found")
}
return &apiv2pb.GetWebhookResponse{
Webhook: convertWebhookFromStore(webhook),
}, nil
}
func (s *APIV2Service) UpdateWebhook(ctx context.Context, request *apiv2pb.UpdateWebhookRequest) (*apiv2pb.UpdateWebhookResponse, error) {
if request.UpdateMask == nil || len(request.UpdateMask.Paths) == 0 {
return nil, status.Errorf(codes.InvalidArgument, "update_mask is required")
}
update := &store.UpdateWebhook{}
for _, path := range request.UpdateMask.Paths {
switch path {
case "row_status":
rowStatus := storepb.RowStatus(storepb.RowStatus_value[request.Webhook.RowStatus.String()])
update.RowStatus = &rowStatus
case "name":
update.Name = &request.Webhook.Name
case "url":
update.URL = &request.Webhook.Url
}
}
webhook, err := s.Store.UpdateWebhook(ctx, update)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to update webhook, error: %+v", err)
}
return &apiv2pb.UpdateWebhookResponse{
Webhook: convertWebhookFromStore(webhook),
}, nil
}
func (s *APIV2Service) DeleteWebhook(ctx context.Context, request *apiv2pb.DeleteWebhookRequest) (*apiv2pb.DeleteWebhookResponse, error) {
err := s.Store.DeleteWebhook(ctx, &store.DeleteWebhook{
ID: request.Id,
})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to delete webhook, error: %+v", err)
}
return &apiv2pb.DeleteWebhookResponse{}, nil
}
func convertWebhookFromStore(webhook *storepb.Webhook) *apiv2pb.Webhook {
return &apiv2pb.Webhook{
Id: webhook.Id,
CreatedTime: timestamppb.New(time.Unix(webhook.CreatedTs, 0)),
UpdatedTime: timestamppb.New(time.Unix(webhook.UpdatedTs, 0)),
RowStatus: apiv2pb.RowStatus(webhook.RowStatus),
CreatorId: webhook.CreatorId,
Name: webhook.Name,
Url: webhook.Url,
}
}
syntax = "proto3";
package memos.api.v2;
import "api/v2/common.proto";
import "google/api/annotations.proto";
import "google/protobuf/field_mask.proto";
import "google/protobuf/timestamp.proto";
option go_package = "gen/api/v2";
service WebhookService {
rpc CreateWebhook(CreateWebhookRequest) returns (CreateWebhookResponse) {
option (google.api.http) = {
post: "/api/v2/webhooks"
body: "*"
};
}
rpc GetWebhook(GetWebhookRequest) returns (GetWebhookResponse) {
option (google.api.http) = {get: "/api/v2/webhooks/{id}"};
}
rpc ListWebhooks(ListWebhooksRequest) returns (ListWebhooksResponse) {
option (google.api.http) = {get: "/api/v2/webhooks"};
}
rpc UpdateWebhook(UpdateWebhookRequest) returns (UpdateWebhookResponse) {
option (google.api.http) = {
patch: "/api/v2/webhooks/{webhook.id}"
body: "*"
};
}
rpc DeleteWebhook(DeleteWebhookRequest) returns (DeleteWebhookResponse) {
option (google.api.http) = {delete: "/api/v2/webhooks/{id}"};
}
}
message Webhook {
int32 id = 1;
int32 creator_id = 2;
google.protobuf.Timestamp created_time = 3;
google.protobuf.Timestamp updated_time = 4;
RowStatus row_status = 5;
string name = 6;
string url = 7;
}
message CreateWebhookRequest {
string name = 1;
string url = 2;
}
message CreateWebhookResponse {
Webhook webhook = 1;
}
message GetWebhookRequest {
int32 id = 1;
}
message GetWebhookResponse {
Webhook webhook = 1;
}
message ListWebhooksRequest {
int32 creator_id = 1;
}
message ListWebhooksResponse {
repeated Webhook webhooks = 1;
}
message UpdateWebhookRequest {
Webhook webhook = 1;
google.protobuf.FieldMask update_mask = 2;
}
message UpdateWebhookResponse {
Webhook webhook = 1;
}
message DeleteWebhookRequest {
int32 id = 1;
}
message DeleteWebhookResponse {}
...@@ -104,6 +104,21 @@ ...@@ -104,6 +104,21 @@
- [UserService](#memos-api-v2-UserService) - [UserService](#memos-api-v2-UserService)
- [api/v2/webhook_service.proto](#api_v2_webhook_service-proto)
- [CreateWebhookRequest](#memos-api-v2-CreateWebhookRequest)
- [CreateWebhookResponse](#memos-api-v2-CreateWebhookResponse)
- [DeleteWebhookRequest](#memos-api-v2-DeleteWebhookRequest)
- [DeleteWebhookResponse](#memos-api-v2-DeleteWebhookResponse)
- [GetWebhookRequest](#memos-api-v2-GetWebhookRequest)
- [GetWebhookResponse](#memos-api-v2-GetWebhookResponse)
- [ListWebhooksRequest](#memos-api-v2-ListWebhooksRequest)
- [ListWebhooksResponse](#memos-api-v2-ListWebhooksResponse)
- [UpdateWebhookRequest](#memos-api-v2-UpdateWebhookRequest)
- [UpdateWebhookResponse](#memos-api-v2-UpdateWebhookResponse)
- [Webhook](#memos-api-v2-Webhook)
- [WebhookService](#memos-api-v2-WebhookService)
- [Scalar Value Types](#scalar-value-types) - [Scalar Value Types](#scalar-value-types)
...@@ -1362,6 +1377,204 @@ ...@@ -1362,6 +1377,204 @@
<a name="api_v2_webhook_service-proto"></a>
<p align="right"><a href="#top">Top</a></p>
## api/v2/webhook_service.proto
<a name="memos-api-v2-CreateWebhookRequest"></a>
### CreateWebhookRequest
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| name | [string](#string) | | |
| url | [string](#string) | | |
<a name="memos-api-v2-CreateWebhookResponse"></a>
### CreateWebhookResponse
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| webhook | [Webhook](#memos-api-v2-Webhook) | | |
<a name="memos-api-v2-DeleteWebhookRequest"></a>
### DeleteWebhookRequest
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| id | [int32](#int32) | | |
<a name="memos-api-v2-DeleteWebhookResponse"></a>
### DeleteWebhookResponse
<a name="memos-api-v2-GetWebhookRequest"></a>
### GetWebhookRequest
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| id | [int32](#int32) | | |
<a name="memos-api-v2-GetWebhookResponse"></a>
### GetWebhookResponse
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| webhook | [Webhook](#memos-api-v2-Webhook) | | |
<a name="memos-api-v2-ListWebhooksRequest"></a>
### ListWebhooksRequest
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| creator_id | [int32](#int32) | | |
<a name="memos-api-v2-ListWebhooksResponse"></a>
### ListWebhooksResponse
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| webhooks | [Webhook](#memos-api-v2-Webhook) | repeated | |
<a name="memos-api-v2-UpdateWebhookRequest"></a>
### UpdateWebhookRequest
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| webhook | [Webhook](#memos-api-v2-Webhook) | | |
| update_mask | [google.protobuf.FieldMask](#google-protobuf-FieldMask) | | |
<a name="memos-api-v2-UpdateWebhookResponse"></a>
### UpdateWebhookResponse
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| webhook | [Webhook](#memos-api-v2-Webhook) | | |
<a name="memos-api-v2-Webhook"></a>
### Webhook
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| id | [int32](#int32) | | |
| creator_id | [int32](#int32) | | |
| created_time | [google.protobuf.Timestamp](#google-protobuf-Timestamp) | | |
| updated_time | [google.protobuf.Timestamp](#google-protobuf-Timestamp) | | |
| row_status | [RowStatus](#memos-api-v2-RowStatus) | | |
| name | [string](#string) | | |
| url | [string](#string) | | |
<a name="memos-api-v2-WebhookService"></a>
### WebhookService
| Method Name | Request Type | Response Type | Description |
| ----------- | ------------ | ------------- | ------------|
| CreateWebhook | [CreateWebhookRequest](#memos-api-v2-CreateWebhookRequest) | [CreateWebhookResponse](#memos-api-v2-CreateWebhookResponse) | |
| GetWebhook | [GetWebhookRequest](#memos-api-v2-GetWebhookRequest) | [GetWebhookResponse](#memos-api-v2-GetWebhookResponse) | |
| ListWebhooks | [ListWebhooksRequest](#memos-api-v2-ListWebhooksRequest) | [ListWebhooksResponse](#memos-api-v2-ListWebhooksResponse) | |
| UpdateWebhook | [UpdateWebhookRequest](#memos-api-v2-UpdateWebhookRequest) | [UpdateWebhookResponse](#memos-api-v2-UpdateWebhookResponse) | |
| DeleteWebhook | [DeleteWebhookRequest](#memos-api-v2-DeleteWebhookRequest) | [DeleteWebhookResponse](#memos-api-v2-DeleteWebhookResponse) | |
## Scalar Value Types ## Scalar Value Types
| .proto Type | Notes | C++ | Java | Python | Go | C# | PHP | Ruby | | .proto Type | Notes | C++ | Java | Python | Go | C# | PHP | Ruby |
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment