3
0

upd(sam): refactory repo/svc for stateful contexts, L2

This commit is contained in:
Tit Petric
2018-09-20 17:23:09 +02:00
parent 49c4b0c434
commit 09e4e15306
15 changed files with 256 additions and 171 deletions

View File

@@ -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)

View File

@@ -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,

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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})
}

View File

@@ -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
}

View File

@@ -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)
//

View File

@@ -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
}
)

View File

@@ -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

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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
}