From 09e4e153069bc62094960b04bc7535d76b7472d3 Mon Sep 17 00:00:00 2001 From: Tit Petric Date: Thu, 20 Sep 2018 17:23:09 +0200 Subject: [PATCH] upd(sam): refactory repo/svc for stateful contexts, L2 --- sam/repository/repository.go | 18 +++- sam/rest/channel.go | 13 ++- sam/rest/message.go | 22 ++--- sam/rest/organisation.go | 12 +-- sam/rest/team.go | 16 ++-- sam/rest/user.go | 2 +- sam/service/attachment.go | 48 +++++++---- sam/service/channel.go | 74 +++++++++------- sam/service/interfaces.go | 14 ++- sam/service/message.go | 100 +++++++++++++--------- sam/service/organisation.go | 38 +++++--- sam/service/team.go | 41 +++++---- sam/websocket/session.go | 2 +- sam/websocket/session_incoming_channel.go | 14 +-- sam/websocket/session_incoming_message.go | 13 ++- 15 files changed, 256 insertions(+), 171 deletions(-) diff --git a/sam/repository/repository.go b/sam/repository/repository.go index 778106e9f..17dee4fe0 100644 --- a/sam/repository/repository.go +++ b/sam/repository/repository.go @@ -4,6 +4,8 @@ import ( "context" "github.com/titpetric/factory" + + "github.com/crusttech/crust/internal/auth" ) type ( @@ -15,7 +17,10 @@ type ( } ) -var _db *factory.DB +var ( +_db *factory.DB +_ctx context.Context +) // DB returns a repository-wide singleton DB handle func DB(ctxs ...context.Context) *factory.DB { @@ -24,11 +29,16 @@ func DB(ctxs ...context.Context) *factory.DB { } for _, ctx := range ctxs { _db = _db.With(ctx) + _ctx = ctx break } return _db } +func Identity(ctx context.Context) uint64 { + return auth.GetIdentityFromContext(ctx).Identity() +} + // With updates repository and database contexts func (r *repository) With(ctx context.Context) *repository { res := &repository{ @@ -41,6 +51,12 @@ func (r *repository) With(ctx context.Context) *repository { return res } +// Context returns current active repository context +func (r *repository) Context() context.Context { + return r.ctx +} + + // db returns context-aware db handle func (r *repository) db() *factory.DB { return r.dbh(r.ctx) diff --git a/sam/rest/channel.go b/sam/rest/channel.go index 165f4dcee..bafb1d716 100644 --- a/sam/rest/channel.go +++ b/sam/rest/channel.go @@ -34,7 +34,7 @@ func (ctrl *Channel) Create(ctx context.Context, r *request.ChannelCreate) (inte Topic: r.Topic, } - return ctrl.svc.ch.Create(ctx, channel) + return ctrl.svc.ch.With(ctx).Create(channel) } func (ctrl *Channel) Edit(ctx context.Context, r *request.ChannelEdit) (interface{}, error) { @@ -44,20 +44,20 @@ func (ctrl *Channel) Edit(ctx context.Context, r *request.ChannelEdit) (interfac Topic: r.Topic, } - return ctrl.svc.ch.Update(ctx, channel) + return ctrl.svc.ch.With(ctx).Update(channel) } func (ctrl *Channel) Delete(ctx context.Context, r *request.ChannelDelete) (interface{}, error) { - return nil, ctrl.svc.ch.Delete(ctx, r.ChannelID) + return nil, ctrl.svc.ch.With(ctx).Delete(r.ChannelID) } func (ctrl *Channel) Read(ctx context.Context, r *request.ChannelRead) (interface{}, error) { - return ctrl.svc.ch.FindByID(ctx, r.ChannelID) + return ctrl.svc.ch.With(ctx).FindByID(r.ChannelID) } func (ctrl *Channel) List(ctx context.Context, r *request.ChannelList) (interface{}, error) { - return ctrl.svc.ch.Find(ctx, &types.ChannelFilter{Query: r.Query}) + return ctrl.svc.ch.With(ctx).Find(&types.ChannelFilter{Query: r.Query}) } func (ctrl *Channel) Members(ctx context.Context, r *request.ChannelMembers) (interface{}, error) { @@ -84,8 +84,7 @@ func (ctrl *Channel) Attach(ctx context.Context, r *request.ChannelAttach) (inte defer file.Close() - return ctrl.svc.att.Create( - ctx, + return ctrl.svc.att.With(ctx).Create( r.ChannelID, r.Upload.Filename, r.Upload.Size, diff --git a/sam/rest/message.go b/sam/rest/message.go index 82683b275..8c1103bbe 100644 --- a/sam/rest/message.go +++ b/sam/rest/message.go @@ -25,21 +25,21 @@ func (Message) New() *Message { } func (ctrl *Message) Create(ctx context.Context, r *request.MessageCreate) (interface{}, error) { - return ctrl.svc.msg.Create(ctx, &types.Message{ + return ctrl.svc.msg.With(ctx).Create(&types.Message{ ChannelID: r.ChannelID, Message: r.Message, }) } func (ctrl *Message) History(ctx context.Context, r *request.MessageHistory) (interface{}, error) { - return ctrl.svc.msg.Find(ctx, &types.MessageFilter{ + return ctrl.svc.msg.With(ctx).Find(&types.MessageFilter{ ChannelID: r.ChannelID, FromMessageID: r.LastMessageID, }) } func (ctrl *Message) Edit(ctx context.Context, r *request.MessageEdit) (interface{}, error) { - return ctrl.svc.msg.Update(ctx, &types.Message{ + return ctrl.svc.msg.With(ctx).Update(&types.Message{ ID: r.MessageID, ChannelID: r.ChannelID, Message: r.Message, @@ -47,36 +47,36 @@ func (ctrl *Message) Edit(ctx context.Context, r *request.MessageEdit) (interfac } func (ctrl *Message) Delete(ctx context.Context, r *request.MessageDelete) (interface{}, error) { - return nil, ctrl.svc.msg.Delete(ctx, r.MessageID) + return nil, ctrl.svc.msg.With(ctx).Delete(r.MessageID) } func (ctrl *Message) Search(ctx context.Context, r *request.MessageSearch) (interface{}, error) { - return ctrl.svc.msg.Find(ctx, &types.MessageFilter{ + return ctrl.svc.msg.With(ctx).Find(&types.MessageFilter{ ChannelID: r.ChannelID, Query: r.Query, }) } func (ctrl *Message) Pin(ctx context.Context, r *request.MessagePin) (interface{}, error) { - return nil, ctrl.svc.msg.Pin(ctx, r.MessageID) + return nil, ctrl.svc.msg.With(ctx).Pin(r.MessageID) } func (ctrl *Message) Unpin(ctx context.Context, r *request.MessageUnpin) (interface{}, error) { - return nil, ctrl.svc.msg.Unpin(ctx, r.MessageID) + return nil, ctrl.svc.msg.With(ctx).Unpin(r.MessageID) } func (ctrl *Message) Flag(ctx context.Context, r *request.MessageFlag) (interface{}, error) { - return nil, ctrl.svc.msg.Flag(ctx, r.MessageID) + return nil, ctrl.svc.msg.With(ctx).Flag(r.MessageID) } func (ctrl *Message) Unflag(ctx context.Context, r *request.MessageUnflag) (interface{}, error) { - return nil, ctrl.svc.msg.Unflag(ctx, r.MessageID) + return nil, ctrl.svc.msg.With(ctx).Unflag(r.MessageID) } func (ctrl *Message) React(ctx context.Context, r *request.MessageReact) (interface{}, error) { - return nil, ctrl.svc.msg.React(ctx, r.MessageID, r.Reaction) + return nil, ctrl.svc.msg.With(ctx).React(r.MessageID, r.Reaction) } func (ctrl *Message) Unreact(ctx context.Context, r *request.MessageUnreact) (interface{}, error) { - return nil, ctrl.svc.msg.Unreact(ctx, r.MessageID, r.Reaction) + return nil, ctrl.svc.msg.With(ctx).Unreact(r.MessageID, r.Reaction) } diff --git a/sam/rest/organisation.go b/sam/rest/organisation.go index ad7ec530a..a917539a6 100644 --- a/sam/rest/organisation.go +++ b/sam/rest/organisation.go @@ -25,11 +25,11 @@ func (Organisation) New() *Organisation { } func (ctrl *Organisation) Read(ctx context.Context, r *request.OrganisationRead) (interface{}, error) { - return ctrl.svc.org.FindByID(ctx, r.ID) + return ctrl.svc.org.With(ctx).FindByID(r.ID) } func (ctrl *Organisation) List(ctx context.Context, r *request.OrganisationList) (interface{}, error) { - return ctrl.svc.org.Find(ctx, &types.OrganisationFilter{Query: r.Query}) + return ctrl.svc.org.With(ctx).Find(&types.OrganisationFilter{Query: r.Query}) } func (ctrl *Organisation) Create(ctx context.Context, r *request.OrganisationCreate) (interface{}, error) { @@ -37,7 +37,7 @@ func (ctrl *Organisation) Create(ctx context.Context, r *request.OrganisationCre Name: r.Name, } - return ctrl.svc.org.Create(ctx, org) + return ctrl.svc.org.With(ctx).Create(org) } func (ctrl *Organisation) Edit(ctx context.Context, r *request.OrganisationEdit) (interface{}, error) { @@ -46,13 +46,13 @@ func (ctrl *Organisation) Edit(ctx context.Context, r *request.OrganisationEdit) Name: r.Name, } - return ctrl.svc.org.Update(ctx, org) + return ctrl.svc.org.With(ctx).Update(org) } func (ctrl *Organisation) Remove(ctx context.Context, r *request.OrganisationRemove) (interface{}, error) { - return nil, ctrl.svc.org.Delete(ctx, r.ID) + return nil, ctrl.svc.org.With(ctx).Delete(r.ID) } func (ctrl *Organisation) Archive(ctx context.Context, r *request.OrganisationArchive) (interface{}, error) { - return nil, ctrl.svc.org.Archive(ctx, r.ID) + return nil, ctrl.svc.org.With(ctx).Archive(r.ID) } diff --git a/sam/rest/team.go b/sam/rest/team.go index 355e3d1dc..0284adbf3 100644 --- a/sam/rest/team.go +++ b/sam/rest/team.go @@ -27,11 +27,11 @@ func (Team) New() *Team { } func (ctrl *Team) Read(ctx context.Context, r *request.TeamRead) (interface{}, error) { - return ctrl.svc.team.FindByID(ctx, r.TeamID) + return ctrl.svc.team.With(ctx).FindByID(r.TeamID) } func (ctrl *Team) List(ctx context.Context, r *request.TeamList) (interface{}, error) { - return ctrl.svc.team.Find(ctx, &types.TeamFilter{Query: r.Query}) + return ctrl.svc.team.With(ctx).Find(&types.TeamFilter{Query: r.Query}) } func (ctrl *Team) Create(ctx context.Context, r *request.TeamCreate) (interface{}, error) { @@ -39,7 +39,7 @@ func (ctrl *Team) Create(ctx context.Context, r *request.TeamCreate) (interface{ Name: r.Name, } - return ctrl.svc.team.Create(ctx, org) + return ctrl.svc.team.With(ctx).Create(org) } func (ctrl *Team) Edit(ctx context.Context, r *request.TeamEdit) (interface{}, error) { @@ -48,21 +48,21 @@ func (ctrl *Team) Edit(ctx context.Context, r *request.TeamEdit) (interface{}, e Name: r.Name, } - return ctrl.svc.team.Update(ctx, org) + return ctrl.svc.team.With(ctx).Update(org) } func (ctrl *Team) Remove(ctx context.Context, r *request.TeamRemove) (interface{}, error) { - return nil, ctrl.svc.team.Delete(ctx, r.TeamID) + return nil, ctrl.svc.team.With(ctx).Delete(r.TeamID) } func (ctrl *Team) Archive(ctx context.Context, r *request.TeamArchive) (interface{}, error) { - return nil, ctrl.svc.team.Archive(ctx, r.TeamID) + return nil, ctrl.svc.team.With(ctx).Archive(r.TeamID) } func (ctrl *Team) Merge(ctx context.Context, r *request.TeamMerge) (interface{}, error) { - return nil, ctrl.svc.team.Merge(ctx, r.TeamID, r.Destination) + return nil, ctrl.svc.team.With(ctx).Merge(r.TeamID, r.Destination) } func (ctrl *Team) Move(ctx context.Context, r *request.TeamMove) (interface{}, error) { - return nil, ctrl.svc.team.Move(ctx, r.TeamID, r.Organisation_id) + return nil, ctrl.svc.team.With(ctx).Move(r.TeamID, r.Organisation_id) } diff --git a/sam/rest/user.go b/sam/rest/user.go index 090348f37..10ba609e9 100644 --- a/sam/rest/user.go +++ b/sam/rest/user.go @@ -35,5 +35,5 @@ func (ctrl *User) Search(ctx context.Context, r *request.UserSearch) (interface{ } func (ctrl *User) Message(ctx context.Context, r *request.UserMessage) (interface{}, error) { - return ctrl.svc.message.Direct(ctx, r.UserID, &types.Message{Message: r.Message}) + return ctrl.svc.message.With(ctx).Direct(r.UserID, &types.Message{Message: r.Message}) } diff --git a/sam/service/attachment.go b/sam/service/attachment.go index ca648baff..994976eed 100644 --- a/sam/service/attachment.go +++ b/sam/service/attachment.go @@ -13,7 +13,6 @@ import ( "github.com/titpetric/factory" - "github.com/crusttech/crust/internal/auth" "github.com/crusttech/crust/internal/store" "github.com/crusttech/crust/sam/repository" "github.com/crusttech/crust/sam/types" @@ -21,9 +20,11 @@ import ( type ( attachment struct { + ctx context.Context + attachment repository.Attachment - message repository.Message - store store.Store + message repository.Message + store store.Store config struct { url string @@ -32,9 +33,11 @@ type ( } AttachmentService interface { + With(ctx context.Context) AttachmentService + FindByID(id uint64) (*types.Attachment, error) - Create(ctx context.Context, channelId uint64, name string, size int64, fh io.ReadSeeker) (*types.Attachment, error) - LoadFromMessages(ctx context.Context, mm types.MessageSet) (err error) + Create(channelId uint64, name string, size int64, fh io.ReadSeeker) (*types.Attachment, error) + LoadFromMessages(mm types.MessageSet) (err error) OpenOriginal(att *types.Attachment) (io.ReadSeeker, error) OpenPreview(att *types.Attachment) (io.ReadSeeker, error) } @@ -42,29 +45,40 @@ type ( func Attachment(store store.Store) *attachment { svc := &attachment{ + ctx: context.Background(), attachment: repository.NewAttachment(context.Background()), - message: repository.NewMessage(context.Background()), - store: store, + message: repository.NewMessage(context.Background()), + store: store, } svc.config.url = "/attachment/%d/%s" svc.config.previewUrl = "/attachment/%d/%s/preview" return svc } -func (svc attachment) FindByID(id uint64) (*types.Attachment, error) { +func (svc *attachment) With(ctx context.Context) AttachmentService { + return &attachment{ + ctx: ctx, + attachment: svc.attachment.With(ctx), + message: svc.message.With(ctx), + store: svc.store, + config: svc.config, + } +} + +func (svc *attachment) FindByID(id uint64) (*types.Attachment, error) { return svc.attachment.FindAttachmentByID(id) } -func (svc attachment) OpenOriginal(att *types.Attachment) (io.ReadSeeker, error) { +func (svc *attachment) OpenOriginal(att *types.Attachment) (io.ReadSeeker, error) { return svc.store.Open(att.Url) } -func (svc attachment) OpenPreview(att *types.Attachment) (io.ReadSeeker, error) { +func (svc *attachment) OpenPreview(att *types.Attachment) (io.ReadSeeker, error) { return svc.store.Open(att.PreviewUrl) } -func (svc attachment) LoadFromMessages(ctx context.Context, mm types.MessageSet) (err error) { +func (svc *attachment) LoadFromMessages(mm types.MessageSet) (err error) { var ids []uint64 mm.Walk(func(m *types.Message) error { if m.Type == types.MessageTypeAttachment || m.Type == types.MessageTypeInlineImage { @@ -91,8 +105,8 @@ func (svc attachment) LoadFromMessages(ctx context.Context, mm types.MessageSet) } } -func (svc attachment) Create(ctx context.Context, channelId uint64, name string, size int64, fh io.ReadSeeker) (att *types.Attachment, err error) { - var currentUserID uint64 = auth.GetIdentityFromContext(ctx).Identity() +func (svc *attachment) Create(channelId uint64, name string, size int64, fh io.ReadSeeker) (att *types.Attachment, err error) { + var currentUserID uint64 = repository.Identity(svc.ctx) // @todo verify if current user can access this channel // @todo verify if current user can upload to this channel @@ -161,16 +175,16 @@ func (svc attachment) Create(ctx context.Context, channelId uint64, name string, } // Generates URL to a location -func (svc attachment) url(att *types.Attachment) string { +func (svc *attachment) url(att *types.Attachment) string { return fmt.Sprintf(svc.config.url, att.ID, url.PathEscape(att.Name)) } // Generates URL to a location -func (svc attachment) previewUrl(att *types.Attachment) string { +func (svc *attachment) previewUrl(att *types.Attachment) string { return fmt.Sprintf(svc.config.previewUrl, att.ID, url.PathEscape(att.Name)) } -func (svc attachment) extractMeta(att *types.Attachment, file io.ReadSeeker) (err error) { +func (svc *attachment) extractMeta(att *types.Attachment, file io.ReadSeeker) (err error) { if _, err = file.Seek(0, 0); err != nil { return err } @@ -208,7 +222,7 @@ func (svc attachment) extractMeta(att *types.Attachment, file io.ReadSeeker) (er return } -func (svc attachment) makePreview(att *types.Attachment, original io.ReadSeeker) (err error) { +func (svc *attachment) makePreview(att *types.Attachment, original io.ReadSeeker) (err error) { if true { return } diff --git a/sam/service/channel.go b/sam/service/channel.go index f1dc65781..2715401d7 100644 --- a/sam/service/channel.go +++ b/sam/service/channel.go @@ -3,37 +3,43 @@ package service import ( "context" "fmt" - "github.com/crusttech/crust/internal/auth" + + "github.com/pkg/errors" + "github.com/crusttech/crust/sam/repository" "github.com/crusttech/crust/sam/types" - "github.com/pkg/errors" ) type ( channel struct { + ctx context.Context + channel repository.Channel message repository.Message } ChannelService interface { - FindByID(ctx context.Context, channelID uint64) (*types.Channel, error) - Find(ctx context.Context, filter *types.ChannelFilter) ([]*types.Channel, error) - FindByMembership(ctx context.Context) (rval []*types.Channel, err error) + With(ctx context.Context) ChannelService - Create(ctx context.Context, channel *types.Channel) (*types.Channel, error) - Update(ctx context.Context, channel *types.Channel) (*types.Channel, error) + FindByID(channelID uint64) (*types.Channel, error) + Find(filter *types.ChannelFilter) ([]*types.Channel, error) + FindByMembership() (rval []*types.Channel, err error) + + Create(channel *types.Channel) (*types.Channel, error) + Update(channel *types.Channel) (*types.Channel, error) deleter archiver } //channelSecurity interface { - // CanRead(ctx context.Context, ch *types.Channel) bool + // CanRead(ch *types.Channel) bool //} ) func Channel() *channel { var svc = &channel{ + ctx: context.Background(), channel: repository.NewChannel(context.Background()), message: repository.NewMessage(context.Background()), } @@ -41,7 +47,15 @@ func Channel() *channel { return svc } -func (svc channel) FindByID(ctx context.Context, id uint64) (ch *types.Channel, err error) { +func (svc *channel) With(ctx context.Context) ChannelService { + return &channel{ + ctx: ctx, + channel: svc.channel.With(ctx), + message: svc.message.With(ctx), + } +} + +func (svc *channel) FindByID(id uint64) (ch *types.Channel, err error) { ch, err = svc.channel.FindChannelByID(id) if err != nil { return @@ -54,24 +68,24 @@ func (svc channel) FindByID(ctx context.Context, id uint64) (ch *types.Channel, return } -func (svc channel) Find(ctx context.Context, filter *types.ChannelFilter) ([]*types.Channel, error) { +func (svc *channel) Find(filter *types.ChannelFilter) ([]*types.Channel, error) { // @todo: permission check to return only channels that channel has access to if cc, err := svc.channel.FindChannels(filter); err != nil { return nil, err } else { - return cc, svc.preloadMembers(ctx, cc) + return cc, svc.preloadMembers(cc) } } -func (svc channel) preloadMembers(ctx context.Context, set types.ChannelSet) error { +func (svc *channel) preloadMembers(set types.ChannelSet) error { // @todo implement return nil } // Returns all channels with membership info -func (svc channel) FindByMembership(ctx context.Context) (rval []*types.Channel, err error) { +func (svc *channel) FindByMembership() (rval []*types.Channel, err error) { return rval, repository.DB().Transaction(func() error { - var chMemberId = auth.GetIdentityFromContext(ctx).Identity() + var chMemberId = repository.Identity(svc.ctx) var mm []*types.ChannelMember if mm, err = svc.channel.FindChannelsMembershipsByMemberId(chMemberId); err != nil { @@ -94,7 +108,7 @@ func (svc channel) FindByMembership(ctx context.Context) (rval []*types.Channel, }) } -func (svc channel) Create(ctx context.Context, in *types.Channel) (out *types.Channel, err error) { +func (svc *channel) Create(in *types.Channel) (out *types.Channel, err error) { // @todo: [SECURITY] permission check if user can add channel return out, repository.DB().Transaction(func() (err error) { @@ -103,7 +117,7 @@ func (svc channel) Create(ctx context.Context, in *types.Channel) (out *types.Ch // @todo get organisation from somewhere var organisationID uint64 = 0 - var chCreatorID = auth.GetIdentityFromContext(ctx).Identity() + var chCreatorID = repository.Identity(svc.ctx) // @todo [SECURITY] check if channel topic can be set if in.Topic != "" && false { @@ -173,7 +187,7 @@ func (svc channel) Create(ctx context.Context, in *types.Channel) (out *types.Ch }) } -func (svc channel) Update(ctx context.Context, in *types.Channel) (out *types.Channel, err error) { +func (svc *channel) Update(in *types.Channel) (out *types.Channel, err error) { return out, repository.DB().Transaction(func() (err error) { var msgs types.MessageSet @@ -188,7 +202,7 @@ func (svc channel) Update(ctx context.Context, in *types.Channel) (out *types.Ch return errors.New("Not allowed to edit deleted channels") } - var chUpdatorId = auth.GetIdentityFromContext(ctx).Identity() + var chUpdatorId = repository.Identity(svc.ctx) // Copy values if out.Name != in.Name { @@ -256,9 +270,9 @@ func (svc channel) Update(ctx context.Context, in *types.Channel) (out *types.Ch }) } -func (svc channel) Delete(ctx context.Context, id uint64) error { +func (svc *channel) Delete(id uint64) error { return repository.DB().Transaction(func() (err error) { - var userID = auth.GetIdentityFromContext(ctx).Identity() + var userID = repository.Identity(svc.ctx) var ch *types.Channel // @todo [SECURITY] can user access this channel? @@ -278,9 +292,9 @@ func (svc channel) Delete(ctx context.Context, id uint64) error { }) } -func (svc channel) Recover(ctx context.Context, id uint64) error { +func (svc *channel) Recover(id uint64) error { return repository.DB().Transaction(func() (err error) { - var userID = auth.GetIdentityFromContext(ctx).Identity() + var userID = repository.Identity(svc.ctx) var ch *types.Channel // @todo [SECURITY] can user access this channel? @@ -300,9 +314,9 @@ func (svc channel) Recover(ctx context.Context, id uint64) error { }) } -func (svc channel) Archive(ctx context.Context, id uint64) error { +func (svc *channel) Archive(id uint64) error { return repository.DB().Transaction(func() (err error) { - var userID = auth.GetIdentityFromContext(ctx).Identity() + var userID = repository.Identity(svc.ctx) var ch *types.Channel // @todo [SECURITY] can user access this channel? @@ -322,9 +336,9 @@ func (svc channel) Archive(ctx context.Context, id uint64) error { }) } -func (svc channel) Unarchive(ctx context.Context, id uint64) error { +func (svc *channel) Unarchive(id uint64) error { return repository.DB().Transaction(func() (err error) { - var userID = auth.GetIdentityFromContext(ctx).Identity() + var userID = repository.Identity(svc.ctx) var ch *types.Channel // @todo [SECURITY] can user access this channel? @@ -345,7 +359,7 @@ func (svc channel) Unarchive(ctx context.Context, id uint64) error { } -func (svc channel) makeSystemMessage(ch *types.Channel, format string, a ...interface{}) *types.Message { +func (svc *channel) makeSystemMessage(ch *types.Channel, format string, a ...interface{}) *types.Message { return &types.Message{ ChannelID: ch.ID, Message: fmt.Sprintf(format, a...), @@ -361,7 +375,7 @@ func (svc channel) makeSystemMessage(ch *types.Channel, format string, a ...inte // } // // nativeChannelSecChRepo interface { -// FindMember(ctx context.Context, channelId uint64, userId uint64) (*types.User, error) +// FindMember(channelId uint64, userId uint64) (*types.User, error) // } //) // @@ -374,10 +388,10 @@ func (svc channel) makeSystemMessage(ch *types.Channel, format string, a ...inte //} // //// Current user can read the channel if he is a member -//func (sec nativeChannelSec) CanRead(ctx context.Context, ch *types.Channel) bool { +//func (sec nativeChannelSec) CanRead(ch *types.Channel) bool { // // @todo check if channel is public? // -// var currentUserID = auth.GetIdentityFromContext(ctx).Identity() +// var currentUserID = repository.Identity(svc.ctx) // // user, err := sec.rpo.FindMember(ch.ID, currentUserID) // diff --git a/sam/service/interfaces.go b/sam/service/interfaces.go index a856ca682..ec0d69f0e 100644 --- a/sam/service/interfaces.go +++ b/sam/service/interfaces.go @@ -1,21 +1,17 @@ package service -import ( - "context" -) - type ( suspender interface { - Suspend(ctx context.Context, ID uint64) error - Unsuspend(ctx context.Context, ID uint64) error + Suspend(ID uint64) error + Unsuspend(ID uint64) error } archiver interface { - Archive(ctx context.Context, ID uint64) error - Unarchive(ctx context.Context, ID uint64) error + Archive(ID uint64) error + Unarchive(ID uint64) error } deleter interface { - Delete(ctx context.Context, ID uint64) error + Delete(ID uint64) error } ) diff --git a/sam/service/message.go b/sam/service/message.go index 1de09f6d7..451be0b2c 100644 --- a/sam/service/message.go +++ b/sam/service/message.go @@ -2,38 +2,43 @@ package service import ( "context" - "github.com/crusttech/crust/internal/auth" - "github.com/crusttech/crust/sam/repository" - "github.com/crusttech/crust/sam/types" + "github.com/davecgh/go-spew/spew" "github.com/pkg/errors" + + "github.com/crusttech/crust/sam/repository" + "github.com/crusttech/crust/sam/types" ) type ( message struct { - channel repository.Channel - message repository.Message + ctx context.Context + + channel repository.Channel + message repository.Message reaction repository.Reaction att AttachmentService } MessageService interface { - Find(ctx context.Context, filter *types.MessageFilter) (types.MessageSet, error) + With(ctx context.Context) MessageService - Create(ctx context.Context, messages *types.Message) (*types.Message, error) - Update(ctx context.Context, messages *types.Message) (*types.Message, error) + Find(filter *types.MessageFilter) (types.MessageSet, error) - React(ctx context.Context, messageID uint64, reaction string) error - Unreact(ctx context.Context, messageID uint64, reaction string) error + Create(messages *types.Message) (*types.Message, error) + Update(messages *types.Message) (*types.Message, error) - Pin(ctx context.Context, messageID uint64) error - Unpin(ctx context.Context, messageID uint64) error + React(messageID uint64, reaction string) error + Unreact(messageID uint64, reaction string) error - Flag(ctx context.Context, messageID uint64) error - Unflag(ctx context.Context, messageID uint64) error + Pin(messageID uint64) error + Unpin(messageID uint64) error - Direct(ctx context.Context, recipientID uint64, in *types.Message) (out *types.Message, err error) + Flag(messageID uint64) error + Unflag(messageID uint64) error + + Direct(recipientID uint64, in *types.Message) (out *types.Message, err error) deleter } @@ -41,15 +46,28 @@ type ( func Message(attSvc AttachmentService) *message { m := &message{ - att: attSvc, - message: repository.NewMessage(context.Background()), + ctx: context.Background(), + att: attSvc, + channel: repository.NewChannel(context.Background()), + message: repository.NewMessage(context.Background()), + reaction: repository.NewReaction(context.Background()), } return m } -func (svc message) Find(ctx context.Context, filter *types.MessageFilter) (mm types.MessageSet, err error) { +func (svc *message) With(ctx context.Context) MessageService { + return &message{ + ctx: ctx, + att: svc.att, + channel: svc.channel.With(ctx), + message: svc.message.With(ctx), + reaction: svc.reaction.With(ctx), + } +} + +func (svc *message) Find(filter *types.MessageFilter) (mm types.MessageSet, err error) { // @todo get user from context - var currentUserID uint64 = auth.GetIdentityFromContext(ctx).Identity() + var currentUserID uint64 = repository.Identity(svc.ctx) // @todo verify if current user can access & read from this channel _ = currentUserID @@ -60,12 +78,12 @@ func (svc message) Find(ctx context.Context, filter *types.MessageFilter) (mm ty return nil, err } - return mm, svc.att.LoadFromMessages(ctx, mm) + return mm, svc.att.LoadFromMessages(mm) } -func (svc message) Direct(ctx context.Context, recipientID uint64, in *types.Message) (out *types.Message, err error) { +func (svc *message) Direct(recipientID uint64, in *types.Message) (out *types.Message, err error) { return out, repository.DB().Transaction(func() (err error) { - var currentUserID = auth.GetIdentityFromContext(ctx).Identity() + var currentUserID = repository.Identity(svc.ctx) // @todo [SECURITY] verify if current user can send direct messages to anyone? if false { @@ -118,9 +136,9 @@ func (svc message) Direct(ctx context.Context, recipientID uint64, in *types.Mes }) } -func (svc message) Create(ctx context.Context, mod *types.Message) (*types.Message, error) { +func (svc *message) Create(mod *types.Message) (*types.Message, error) { // @todo get user from context - var currentUserID uint64 = auth.GetIdentityFromContext(ctx).Identity() + var currentUserID uint64 = repository.Identity(svc.ctx) // @todo verify if current user can access & write to this channel @@ -128,14 +146,14 @@ func (svc message) Create(ctx context.Context, mod *types.Message) (*types.Messa message, err := svc.message.CreateMessage(mod) if err == nil { - PubSub().Event(ctx, "new message added") + PubSub().Event(svc.ctx, "new message added") } return message, err } -func (svc message) Update(ctx context.Context, mod *types.Message) (*types.Message, error) { +func (svc *message) Update(mod *types.Message) (*types.Message, error) { // @todo get user from context - var currentUserID uint64 = auth.GetIdentityFromContext(ctx).Identity() + var currentUserID uint64 = repository.Identity(svc.ctx) // @todo verify if current user can access & write to this channel _ = currentUserID @@ -147,9 +165,9 @@ func (svc message) Update(ctx context.Context, mod *types.Message) (*types.Messa return svc.message.UpdateMessage(mod) } -func (svc message) Delete(ctx context.Context, id uint64) error { +func (svc *message) Delete(id uint64) error { // @todo get user from context - var currentUserID uint64 = auth.GetIdentityFromContext(ctx).Identity() + var currentUserID uint64 = repository.Identity(svc.ctx) // @todo verify if current user can access & write to this channel _ = currentUserID @@ -161,9 +179,9 @@ func (svc message) Delete(ctx context.Context, id uint64) error { return svc.message.DeleteMessageByID(id) } -func (svc message) React(ctx context.Context, messageID uint64, reaction string) error { +func (svc *message) React(messageID uint64, reaction string) error { // @todo get user from context - var currentUserID uint64 = auth.GetIdentityFromContext(ctx).Identity() + var currentUserID uint64 = repository.Identity(svc.ctx) // @todo verify if current user can access & write to this channel var m *types.Message @@ -184,9 +202,9 @@ func (svc message) React(ctx context.Context, messageID uint64, reaction string) return nil } -func (svc message) Unreact(ctx context.Context, messageID uint64, reaction string) error { +func (svc *message) Unreact(messageID uint64, reaction string) error { // @todo get user from context - var currentUserID uint64 = auth.GetIdentityFromContext(ctx).Identity() + var currentUserID uint64 = repository.Identity(svc.ctx) // @todo verify if current user can access & write to this channel _ = currentUserID @@ -197,9 +215,9 @@ func (svc message) Unreact(ctx context.Context, messageID uint64, reaction strin return svc.reaction.DeleteReactionByID(r.ID) } -func (svc message) Pin(ctx context.Context, messageID uint64) error { +func (svc *message) Pin(messageID uint64) error { // @todo get user from context - var currentUserID uint64 = auth.GetIdentityFromContext(ctx).Identity() + var currentUserID uint64 = repository.Identity(svc.ctx) // @todo verify if current user can access & write to this channel _ = currentUserID @@ -207,9 +225,9 @@ func (svc message) Pin(ctx context.Context, messageID uint64) error { return nil } -func (svc message) Unpin(ctx context.Context, messageID uint64) error { +func (svc *message) Unpin(messageID uint64) error { // @todo get user from context - var currentUserID uint64 = auth.GetIdentityFromContext(ctx).Identity() + var currentUserID uint64 = repository.Identity(svc.ctx) // @todo verify if current user can access & write to this channel _ = currentUserID @@ -217,9 +235,9 @@ func (svc message) Unpin(ctx context.Context, messageID uint64) error { return nil } -func (svc message) Flag(ctx context.Context, messageID uint64) error { +func (svc *message) Flag(messageID uint64) error { // @todo get user from context - var currentUserID uint64 = auth.GetIdentityFromContext(ctx).Identity() + var currentUserID uint64 = repository.Identity(svc.ctx) // @todo verify if current user can access & write to this channel _ = currentUserID @@ -227,9 +245,9 @@ func (svc message) Flag(ctx context.Context, messageID uint64) error { return nil } -func (svc message) Unflag(ctx context.Context, messageID uint64) error { +func (svc *message) Unflag(messageID uint64) error { // @todo get user from context - var currentUserID uint64 = auth.GetIdentityFromContext(ctx).Identity() + var currentUserID uint64 = repository.Identity(svc.ctx) // @todo verify if current user can access & write to this channel _ = currentUserID diff --git a/sam/service/organisation.go b/sam/service/organisation.go index 4f80be418..104f8735a 100644 --- a/sam/service/organisation.go +++ b/sam/service/organisation.go @@ -2,21 +2,25 @@ package service import ( "context" + "github.com/crusttech/crust/sam/repository" "github.com/crusttech/crust/sam/types" ) type ( organisation struct { + ctx context.Context rpo repository.Organisation } OrganisationService interface { - FindByID(ctx context.Context, organisationID uint64) (*types.Organisation, error) - Find(ctx context.Context, filter *types.OrganisationFilter) ([]*types.Organisation, error) + With(ctx context.Context) OrganisationService - Create(ctx context.Context, organisation *types.Organisation) (*types.Organisation, error) - Update(ctx context.Context, organisation *types.Organisation) (*types.Organisation, error) + FindByID(organisationID uint64) (*types.Organisation, error) + Find(filter *types.OrganisationFilter) ([]*types.Organisation, error) + + Create(organisation *types.Organisation) (*types.Organisation, error) + Update(organisation *types.Organisation) (*types.Organisation, error) deleter archiver @@ -24,49 +28,59 @@ type ( ) func Organisation() *organisation { - return &organisation{rpo: repository.NewOrganisation(context.Background())} + return &organisation{ + ctx: context.Background(), + rpo: repository.NewOrganisation(context.Background()), + } } -func (svc organisation) FindByID(ctx context.Context, id uint64) (*types.Organisation, error) { +func (svc *organisation) With(ctx context.Context) OrganisationService { + return &organisation{ + ctx: ctx, + rpo: svc.rpo.With(ctx), + } +} + +func (svc *organisation) FindByID(id uint64) (*types.Organisation, error) { // @todo: permission check if current user can read organisation return svc.rpo.FindOrganisationByID(id) } -func (svc organisation) Find(ctx context.Context, filter *types.OrganisationFilter) ([]*types.Organisation, error) { +func (svc *organisation) Find(filter *types.OrganisationFilter) ([]*types.Organisation, error) { // @todo: permission check to return only organisations that organisation has access to // @todo: actual searching not just a full select return svc.rpo.FindOrganisations(filter) } -func (svc organisation) Create(ctx context.Context, mod *types.Organisation) (*types.Organisation, error) { +func (svc *organisation) Create(mod *types.Organisation) (*types.Organisation, error) { // @todo: permission check if current user can add/edit organisation // @todo: make sure archived & deleted entries can not be edited return svc.rpo.CreateOrganisation(mod) } -func (svc organisation) Update(ctx context.Context, mod *types.Organisation) (*types.Organisation, error) { +func (svc *organisation) Update(mod *types.Organisation) (*types.Organisation, error) { // @todo: permission check if current user can add/edit organisation // @todo: make sure archived & deleted entries can not be edited return svc.rpo.UpdateOrganisation(mod) } -func (svc organisation) Delete(ctx context.Context, id uint64) error { +func (svc *organisation) Delete(id uint64) error { // @todo: permissions check if current user can remove organisation // @todo: make history unavailable // @todo: notify users that organisation has been removed (remove from web UI) return svc.rpo.DeleteOrganisationByID(id) } -func (svc organisation) Archive(ctx context.Context, id uint64) error { +func (svc *organisation) Archive(id uint64) error { // @todo: make history unavailable // @todo: notify users that organisation has been removed (remove from web UI) // @todo: permissions check if current user can archive organisation return svc.rpo.ArchiveOrganisationByID(id) } -func (svc organisation) Unarchive(ctx context.Context, id uint64) error { +func (svc *organisation) Unarchive(id uint64) error { // @todo: make history unavailable // @todo: notify users that organisation has been removed (remove from web UI) // @todo: permissions check if current user can unarchive organisation diff --git a/sam/service/team.go b/sam/service/team.go index d783597d8..e853daaca 100644 --- a/sam/service/team.go +++ b/sam/service/team.go @@ -8,17 +8,20 @@ import ( type ( team struct { + ctx context.Context team repository.Team } TeamService interface { - FindByID(ctx context.Context, teamID uint64) (*types.Team, error) - Find(ctx context.Context, filter *types.TeamFilter) ([]*types.Team, error) + With(ctx context.Context) TeamService - Create(ctx context.Context, team *types.Team) (*types.Team, error) - Update(ctx context.Context, team *types.Team) (*types.Team, error) - Merge(ctx context.Context, teamID, targetTeamID uint64) error - Move(ctx context.Context, teamID, organisationID uint64) error + FindByID(teamID uint64) (*types.Team, error) + Find(filter *types.TeamFilter) ([]*types.Team, error) + + Create(team *types.Team) (*types.Team, error) + Update(team *types.Team) (*types.Team, error) + Merge(teamID, targetTeamID uint64) error + Move(teamID, organisationID uint64) error deleter archiver @@ -27,60 +30,68 @@ type ( func Team() *team { return &team{ + ctx: context.Background(), team: repository.NewTeam(context.Background()), } } -func (svc team) FindByID(ctx context.Context, id uint64) (*types.Team, error) { +func (svc *team) With(ctx context.Context) TeamService { + return &team{ + ctx: ctx, + team: svc.team.With(ctx), + } +} + +func (svc *team) FindByID(id uint64) (*types.Team, error) { // @todo: permission check if current user has access to this team return svc.team.FindTeamByID(id) } -func (svc team) Find(ctx context.Context, filter *types.TeamFilter) ([]*types.Team, error) { +func (svc *team) Find(filter *types.TeamFilter) ([]*types.Team, error) { // @todo: permission check to return only teams that current user has access to return svc.team.FindTeams(filter) } -func (svc team) Create(ctx context.Context, mod *types.Team) (*types.Team, error) { +func (svc *team) Create(mod *types.Team) (*types.Team, error) { // @todo: permission check if current user can add/edit team return svc.team.CreateTeam(mod) } -func (svc team) Update(ctx context.Context, mod *types.Team) (*types.Team, error) { +func (svc *team) Update(mod *types.Team) (*types.Team, error) { // @todo: permission check if current user can add/edit team // @todo: make sure archived & deleted entries can not be edited return svc.team.UpdateTeam(mod) } -func (svc team) Delete(ctx context.Context, id uint64) error { +func (svc *team) Delete(id uint64) error { // @todo: make history unavailable // @todo: notify users that team has been removed (remove from web UI) // @todo: permissions check if current user can remove team return svc.team.DeleteTeamByID(id) } -func (svc team) Archive(ctx context.Context, id uint64) error { +func (svc *team) Archive(id uint64) error { // @todo: make history unavailable // @todo: notify users that team has been removed (remove from web UI) // @todo: permissions check if current user can remove team return svc.team.ArchiveTeamByID(id) } -func (svc team) Unarchive(ctx context.Context, id uint64) error { +func (svc *team) Unarchive(id uint64) error { // @todo: permissions check if current user can unarchive team // @todo: make history accessible // @todo: notify users that team has been unarchived return svc.team.UnarchiveTeamByID(id) } -func (svc team) Merge(ctx context.Context, id, targetTeamID uint64) error { +func (svc *team) Merge(id, targetTeamID uint64) error { // @todo: permission check if current user can merge team return svc.team.MergeTeamByID(id, targetTeamID) } -func (svc team) Move(ctx context.Context, id, targetOrganisationID uint64) error { +func (svc *team) Move(id, targetOrganisationID uint64) error { // @todo: permission check if current user can move team to another organisation return svc.team.MoveTeamByID(id, targetOrganisationID) } diff --git a/sam/websocket/session.go b/sam/websocket/session.go index 06d5e9ebb..f8487ebc5 100644 --- a/sam/websocket/session.go +++ b/sam/websocket/session.go @@ -65,7 +65,7 @@ func (sess *Session) connected() { sess.sendToAll(&outgoing.Connected{UserID: uint64toa(sess.user.Identity())}) // Subscribe this user to all channels - if chs, err := sess.svc.ch.FindByMembership(sess.ctx); err != nil { + if chs, err := sess.svc.ch.With(sess.ctx).FindByMembership(); err != nil { log.Printf("Error: %v", err) } else { for _, ch := range chs { diff --git a/sam/websocket/session_incoming_channel.go b/sam/websocket/session_incoming_channel.go index fd9245593..e315d3d53 100644 --- a/sam/websocket/session_incoming_channel.go +++ b/sam/websocket/session_incoming_channel.go @@ -9,6 +9,10 @@ import ( "github.com/crusttech/crust/sam/websocket/outgoing" ) +func channelService(ctx context.Context) service.ChannelService { + return service.Channel().With(ctx) +} + func (s *Session) channelJoin(ctx context.Context, p *incoming.ChannelJoin) error { // @todo: check access / can we join this channel (should be done by service layer) @@ -44,7 +48,7 @@ func (s *Session) channelPart(ctx context.Context, p *incoming.ChannelPart) erro } func (s *Session) channelList(ctx context.Context, p *incoming.Channels) error { - channels, err := service.Channel().Find(ctx, &types.ChannelFilter{IncludeMembers: true}) + channels, err := channelService(ctx).Find(&types.ChannelFilter{IncludeMembers: true}) if err != nil { return err } @@ -71,7 +75,7 @@ func (s *Session) channelCreate(ctx context.Context, p *incoming.ChannelCreate) ch.Type = types.ChannelType(*p.Type) } - ch, err = service.Channel().Create(ctx, ch) + ch, err = channelService(ctx).Create(ch) if err != nil { return err } @@ -94,7 +98,7 @@ func (s *Session) channelCreate(ctx context.Context, p *incoming.ChannelCreate) } func (s *Session) channelDelete(ctx context.Context, p *incoming.ChannelDelete) (err error) { - err = service.Channel().Delete(ctx, parseUInt64(p.ChannelID)) + err = channelService(ctx).Delete(parseUInt64(p.ChannelID)) if err != nil { return err } @@ -106,7 +110,7 @@ func (s *Session) channelDelete(ctx context.Context, p *incoming.ChannelDelete) } func (s *Session) channelUpdate(ctx context.Context, p *incoming.ChannelUpdate) error { - ch, err := service.Channel().FindByID(ctx, parseUInt64(p.ID)) + ch, err := channelService(ctx).FindByID(parseUInt64(p.ID)) if err != nil { return err } @@ -123,7 +127,7 @@ func (s *Session) channelUpdate(ctx context.Context, p *incoming.ChannelUpdate) ch.Type = types.ChannelType(*p.Type) } - ch, err = service.Channel().Update(ctx, ch) + ch, err = channelService(ctx).Update(ch) if err != nil { return err } diff --git a/sam/websocket/session_incoming_message.go b/sam/websocket/session_incoming_message.go index 5cd67a3f9..361758611 100644 --- a/sam/websocket/session_incoming_message.go +++ b/sam/websocket/session_incoming_message.go @@ -11,13 +11,12 @@ import ( fstore "github.com/crusttech/crust/internal/store" ) -func messageService() service.MessageService { +func messageService(ctx context.Context) service.MessageService { // @todo refactor, optimize this store, _ := fstore.New("var/store") attSvc := service.Attachment(store) msgSvc := service.Message(attSvc) - - return msgSvc + return msgSvc.With(ctx) } func (s *Session) messageCreate(ctx context.Context, p *incoming.MessageCreate) error { @@ -28,7 +27,7 @@ func (s *Session) messageCreate(ctx context.Context, p *incoming.MessageCreate) } ) - msg, err := messageService().Create(ctx, msg) + msg, err := messageService(ctx).Create(msg) if err != nil { return err } @@ -43,7 +42,7 @@ func (s *Session) messageUpdate(ctx context.Context, p *incoming.MessageUpdate) Message: p.Message, } ) - msg, err := messageService().Update(ctx, msg) + msg, err := messageService(ctx).Update(msg) if err != nil { return err } @@ -62,7 +61,7 @@ func (s *Session) messageDelete(ctx context.Context, p *incoming.MessageDelete) id = parseUInt64(p.ID) ) - if err := messageService().Delete(ctx, id); err != nil { + if err := messageService(ctx).Delete(id); err != nil { return err } @@ -81,7 +80,7 @@ func (s *Session) messageHistory(ctx context.Context, p *incoming.Messages) erro } ) - messages, err := messageService().Find(ctx, filter) + messages, err := messageService(ctx).Find(filter) if err != nil { return err }