diff --git a/.drone.yml b/.drone.yml index fa9b3c591..cb5c0b020 100644 --- a/.drone.yml +++ b/.drone.yml @@ -15,6 +15,7 @@ steps: GOARCH: amd64 CI: circleci commands: + - make codegen - make test - name: api-system @@ -99,6 +100,8 @@ steps: COMPOSE_DB_DSN: crust:crust@tcp(crust-db:3306)/crust?collation=utf8mb4_general_ci MESSAGING_DB_DSN: crust:crust@tcp(crust-db:3306)/crust?collation=utf8mb4_general_ci commands: + - make codegen + - go build ./cmd/... - wait-for-it.sh -t 60 --strict crust-db:3306 -- echo "Crust DB1 is up" - gotest -v --tags="migrations" ./system/db/... - gotest -v --tags="migrations" ./compose/db/... diff --git a/api/messaging/spec.json b/api/messaging/spec.json index 74587ee16..9b35c8918 100644 --- a/api/messaging/spec.json +++ b/api/messaging/spec.json @@ -70,7 +70,6 @@ "title": "User activity", "parameters": {}, "authentication": [], - "apis": [ { "name": "send", @@ -914,6 +913,12 @@ "required": true, "title": "Kind (incoming, outgoing)" }, + { + "name": "userID", + "type": "uint64", + "required": true, + "title": "Bot User ID" + }, { "name": "trigger", "type": "string", @@ -974,6 +979,12 @@ "required": true, "title": "Kind (incoming, outgoing)" }, + { + "name": "userID", + "type": "uint64", + "required": true, + "title": "Bot User ID" + }, { "name": "trigger", "type": "string", @@ -1213,4 +1224,4 @@ } ] } -] +] \ No newline at end of file diff --git a/api/messaging/spec/webhooks.json b/api/messaging/spec/webhooks.json index cddc9ab4d..c082d6488 100644 --- a/api/messaging/spec/webhooks.json +++ b/api/messaging/spec/webhooks.json @@ -54,6 +54,12 @@ "title": "Kind (incoming, outgoing)", "type": "types.WebhookKind" }, + { + "name": "userID", + "required": true, + "title": "Bot User ID", + "type": "uint64" + }, { "name": "trigger", "required": false, @@ -114,6 +120,12 @@ "title": "Kind (incoming, outgoing)", "type": "types.WebhookKind" }, + { + "name": "userID", + "required": true, + "title": "Bot User ID", + "type": "uint64" + }, { "name": "trigger", "required": false, diff --git a/docs/messaging/README.md b/docs/messaging/README.md index c763c8c02..04f6957c8 100644 --- a/docs/messaging/README.md +++ b/docs/messaging/README.md @@ -743,6 +743,7 @@ A channel is a representation of a sequence of messages. It has meta data like c | --------- | ---- | ------ | ----------- | ------- | --------- | | channelID | uint64 | POST | Channel ID | N/A | YES | | kind | types.WebhookKind | POST | Kind (incoming, outgoing) | N/A | YES | +| userID | uint64 | POST | Bot User ID | N/A | YES | | trigger | string | POST | Trigger word | N/A | NO | | url | string | POST | POST URL | N/A | NO | | username | string | POST | Default user name | N/A | NO | @@ -764,6 +765,7 @@ A channel is a representation of a sequence of messages. It has meta data like c | webhookID | uint64 | PATH | Webhook ID | N/A | YES | | channelID | uint64 | POST | Channel ID | N/A | YES | | kind | types.WebhookKind | POST | Kind (incoming, outgoing) | N/A | YES | +| userID | uint64 | POST | Bot User ID | N/A | YES | | trigger | string | POST | Trigger word | N/A | NO | | url | string | POST | POST URL | N/A | NO | | username | string | POST | Default user name | N/A | NO | diff --git a/messaging/internal/repository/main_test.go b/messaging/internal/repository/main_test.go index 0ef7438ae..c7d28ac4d 100644 --- a/messaging/internal/repository/main_test.go +++ b/messaging/internal/repository/main_test.go @@ -10,8 +10,7 @@ import ( "github.com/namsral/flag" "github.com/titpetric/factory" - messagingMigrate "github.com/crusttech/crust/messaging/db" - systemMigrate "github.com/crusttech/crust/system/db" + migrate "github.com/crusttech/crust/messaging/db" ) func TestMain(m *testing.M) { @@ -22,17 +21,12 @@ func TestMain(m *testing.M) { factory.Database.Add("default", dsn) factory.Database.Add("messaging", dsn) - factory.Database.Add("system", dsn) db := factory.Database.MustGet() db.Profiler = &factory.Database.ProfilerStdout // migrate database schema - if err := systemMigrate.Migrate(db); err != nil { - fmt.Printf("Error running migrations: %+v\n", err) - return - } - if err := messagingMigrate.Migrate(db); err != nil { + if err := migrate.Migrate(db); err != nil { fmt.Printf("Error running migrations: %+v\n", err) return } diff --git a/messaging/internal/service/channel_test.go b/messaging/internal/service/channel_test.go index 8ebef8159..51437cf33 100644 --- a/messaging/internal/service/channel_test.go +++ b/messaging/internal/service/channel_test.go @@ -8,12 +8,11 @@ import ( "github.com/crusttech/crust/internal/auth" "github.com/crusttech/crust/internal/test" "github.com/crusttech/crust/messaging/types" - systemTypes "github.com/crusttech/crust/system/types" ) func TestChannelNameTooShort(t *testing.T) { ctx := context.Background() - ctx = auth.SetIdentityToContext(ctx, &systemTypes.User{}) + ctx = auth.SetIdentityToContext(ctx, auth.NewIdentity(1337)) svc := channel{} e := func(out *types.Channel, err error) error { return err } diff --git a/messaging/internal/service/main_test.go b/messaging/internal/service/main_test.go index a5b0d9fcb..b8444fcb0 100644 --- a/messaging/internal/service/main_test.go +++ b/messaging/internal/service/main_test.go @@ -15,8 +15,6 @@ import ( "github.com/crusttech/crust/internal/logger" messagingMigrate "github.com/crusttech/crust/messaging/db" "github.com/crusttech/crust/messaging/internal/repository" - systemMigrate "github.com/crusttech/crust/system/db" - systemService "github.com/crusttech/crust/system/service" ) type mockDB struct{} @@ -33,21 +31,13 @@ func TestMain(m *testing.M) { factory.Database.Add("default", dsn) factory.Database.Add("messaging", dsn) - factory.Database.Add("system", dsn) // @todo: add flags to configure the sql profiler in tests db := factory.Database.MustGet() db.Profiler = &factory.Database.ProfilerStdout - dbSystem := factory.Database.MustGet("system") - dbSystem.Profiler = &factory.Database.ProfilerStdout - // migrate database schema - if err := systemMigrate.Migrate(dbSystem); err != nil { - fmt.Printf("Error running migrations: %+v\n", err) - return - } if err := messagingMigrate.Migrate(db); err != nil { fmt.Printf("Error running migrations: %+v\n", err) return @@ -63,7 +53,6 @@ func TestMain(m *testing.M) { } } - systemService.Init(context.Background()) Init(context.Background()) os.Exit(m.Run()) diff --git a/messaging/internal/service/message_test.go b/messaging/internal/service/message_test.go index dc9dcdfb8..3a315dbbe 100644 --- a/messaging/internal/service/message_test.go +++ b/messaging/internal/service/message_test.go @@ -8,12 +8,11 @@ import ( "github.com/crusttech/crust/internal/auth" "github.com/crusttech/crust/internal/test" "github.com/crusttech/crust/messaging/types" - systemTypes "github.com/crusttech/crust/system/types" ) func TestMessageLength(t *testing.T) { ctx := context.Background() - ctx = auth.SetIdentityToContext(ctx, &systemTypes.User{}) + ctx = auth.SetIdentityToContext(ctx, auth.NewIdentity(1337)) svc := message{} e := func(out *types.Message, err error) error { return err } diff --git a/messaging/internal/service/webhook.go b/messaging/internal/service/webhook.go index c5f447fbc..cd4e4ef51 100644 --- a/messaging/internal/service/webhook.go +++ b/messaging/internal/service/webhook.go @@ -18,8 +18,6 @@ import ( "github.com/crusttech/crust/internal/store" "github.com/crusttech/crust/messaging/internal/repository" "github.com/crusttech/crust/messaging/types" - systemService "github.com/crusttech/crust/system/service" - systemTypes "github.com/crusttech/crust/system/types" ) type ( @@ -30,7 +28,6 @@ type ( client *http.Client - users systemService.UserService webhook repository.WebhookRepository ac webhookAccessController } @@ -77,7 +74,6 @@ func (svc webhook) With(ctx context.Context) WebhookService { client: svc.client, - users: systemService.User(ctx), webhook: repository.Webhook(ctx, db), ac: DefaultAccessControl, } @@ -91,8 +87,11 @@ func (svc webhook) log(fields ...zapcore.Field) *zap.Logger { func (svc webhook) Create(kind types.WebhookKind, channelID uint64, params types.WebhookRequest) (*types.Webhook, error) { var userID = repository.Identity(svc.ctx) + // @todo: params.Avatar (io.Reader) + webhook := &types.Webhook{ Kind: kind, + UserID: params.UserID, OwnerUserID: userID, ChannelID: channelID, OutgoingTrigger: params.OutgoingTrigger, @@ -103,27 +102,7 @@ func (svc webhook) Create(kind types.WebhookKind, channelID uint64, params types return nil, ErrNoPermissions.withStack() } - botUser := &systemTypes.User{ - Username: params.Username, - Name: params.Username, - Handle: params.Username, - Kind: systemTypes.BotUser, - RelatedUserID: userID, - } - - user, err := svc.users.CreateWithAvatar(botUser, params.Avatar) - if err != nil { - return nil, err - } - webhook.UserID = user.ID - - wh, err := svc.webhook.Create(webhook) - if err != nil { - // cross service rollback (delete user) - svc.users.Delete(user.ID) - return nil, err - } - return wh, err + return svc.webhook.Create(webhook) } func (svc webhook) Update(webhookID uint64, kind types.WebhookKind, channelID uint64, params types.WebhookRequest) (*types.Webhook, error) { @@ -140,14 +119,7 @@ func (svc webhook) Update(webhookID uint64, kind types.WebhookKind, channelID ui return nil, ErrNoPermissions.withStack() } - botUser, err := svc.users.FindByID(webhook.UserID) - if err != nil { - return nil, errors.Wrapf(err, "Error when looking for User ID %d", webhook.UserID) - } - - if _, err := svc.users.UpdateWithAvatar(botUser, params.Avatar); err != nil { - return nil, err - } + // @todo: params.Avatar (io.Reader) webhook.Kind = kind webhook.ChannelID = channelID @@ -267,7 +239,7 @@ func (svc webhook) Do(webhook *types.Webhook, message string) (*types.Message, e func (svc webhook) sendMessage(webhook *types.Webhook, msg *types.Message, avatar io.Reader) (*types.Message, error) { // We need a webhook user context for message service - ctx := auth.SetIdentityToContext(svc.ctx, &systemTypes.User{ID: webhook.UserID}) + ctx := auth.SetIdentityToContext(svc.ctx, auth.NewIdentity(webhook.UserID)) messageSvc := Message(ctx) msg.ChannelID = webhook.ChannelID diff --git a/messaging/internal/service/webhook_test.go b/messaging/internal/service/webhook_test.go index fa4b4351d..64cd36a50 100644 --- a/messaging/internal/service/webhook_test.go +++ b/messaging/internal/service/webhook_test.go @@ -13,23 +13,13 @@ import ( "github.com/crusttech/crust/internal/test" "github.com/crusttech/crust/messaging/internal/repository" "github.com/crusttech/crust/messaging/types" - systemService "github.com/crusttech/crust/system/service" - systemTypes "github.com/crusttech/crust/system/types" ) func TestOutgoingWebhook(t *testing.T) { - var user = &systemTypes.User{ID: 1} var channel = &types.Channel{ID: 1} ctx := context.WithValue(context.Background(), "testing", true) - ctx = auth.SetIdentityToContext(ctx, user) - - // set up user - { - svc := systemService.User(ctx) - _, err := svc.Create(user) - test.Assert(t, err == nil, "Error when creating user: %+v", err) - } + ctx = auth.SetIdentityToContext(ctx, auth.NewIdentity(1337)) // set up channel { diff --git a/messaging/rest/request/webhooks.go b/messaging/rest/request/webhooks.go index 9c12373a9..ed471dc5d 100644 --- a/messaging/rest/request/webhooks.go +++ b/messaging/rest/request/webhooks.go @@ -97,6 +97,7 @@ var _ RequestFiller = NewWebhooksList() type WebhooksCreate struct { ChannelID uint64 `json:",string"` Kind types.WebhookKind + UserID uint64 `json:",string"` Trigger string Url string Username string @@ -115,6 +116,8 @@ func (r WebhooksCreate) Auditable() map[string]interface{} { out["kind"] = r.Kind + out["userID"] = r.UserID + out["trigger"] = r.Trigger out["url"] = r.Url @@ -164,6 +167,10 @@ func (r *WebhooksCreate) Fill(req *http.Request) (err error) { r.Kind = types.WebhookKind(val) } + if val, ok := post["userID"]; ok { + + r.UserID = parseUInt64(val) + } if val, ok := post["trigger"]; ok { r.Trigger = val @@ -195,6 +202,7 @@ type WebhooksUpdate struct { WebhookID uint64 `json:",string"` ChannelID uint64 `json:",string"` Kind types.WebhookKind + UserID uint64 `json:",string"` Trigger string Url string Username string @@ -215,6 +223,8 @@ func (r WebhooksUpdate) Auditable() map[string]interface{} { out["kind"] = r.Kind + out["userID"] = r.UserID + out["trigger"] = r.Trigger out["url"] = r.Url @@ -265,6 +275,10 @@ func (r *WebhooksUpdate) Fill(req *http.Request) (err error) { r.Kind = types.WebhookKind(val) } + if val, ok := post["userID"]; ok { + + r.UserID = parseUInt64(val) + } if val, ok := post["trigger"]; ok { r.Trigger = val diff --git a/messaging/rest/router.go b/messaging/rest/router.go index 191caebbd..172d64638 100644 --- a/messaging/rest/router.go +++ b/messaging/rest/router.go @@ -12,9 +12,7 @@ func MountRoutes() func(chi.Router) { return func(r chi.Router) { r.Group(func(r chi.Router) { handlers.NewAttachment(Attachment{}.New()).MountRoutes(r) - }) - - r.Group(func(r chi.Router) { + handlers.NewWebhooksPublic(WebhooksPublic{}.New()).MountRoutes(r) handlers.NewPermissions(Permissions{}.New()).MountRoutes(r) }) @@ -29,6 +27,7 @@ func MountRoutes() func(chi.Router) { handlers.NewSearch(Search{}.New()).MountRoutes(r) handlers.NewStatus(Status{}.New()).MountRoutes(r) handlers.NewCommands(Commands{}.New()).MountRoutes(r) + handlers.NewWebhooks(Webhooks{}.New()).MountRoutes(r) }) } } diff --git a/messaging/rest/webhooks.go b/messaging/rest/webhooks.go index acc4ab14f..314327c35 100644 --- a/messaging/rest/webhooks.go +++ b/messaging/rest/webhooks.go @@ -45,6 +45,7 @@ func (ctrl *Webhooks) Create(ctx context.Context, r *request.WebhooksCreate) (in // Webhook request parameters parameters := types.WebhookRequest{ r.Username, + r.UserID, avatar, r.Trigger, r.Url, @@ -61,6 +62,7 @@ func (ctrl *Webhooks) Update(ctx context.Context, r *request.WebhooksUpdate) (in // Webhook request parameters parameters := types.WebhookRequest{ r.Username, + r.UserID, avatar, r.Trigger, r.Url, diff --git a/messaging/types/webhook.go b/messaging/types/webhook.go index 25961c9b1..f036fdefc 100644 --- a/messaging/types/webhook.go +++ b/messaging/types/webhook.go @@ -29,6 +29,7 @@ type ( WebhookRequest struct { Username string + UserID uint64 Avatar io.Reader