diff --git a/sam/repository/channel.go b/sam/repository/channel.go index 8e1d24611..558440bd3 100644 --- a/sam/repository/channel.go +++ b/sam/repository/channel.go @@ -16,6 +16,7 @@ type ( FindChannelByID(id uint64) (*types.Channel, error) FindDirectChannelByUserID(fromUserID, toUserID uint64) (*types.Channel, error) FindChannels(filter *types.ChannelFilter) ([]*types.Channel, error) + FindMembers(userID uint64) (types.ChannelMemberSet, error) CreateChannel(mod *types.Channel) (*types.Channel, error) UpdateChannel(mod *types.Channel) (*types.Channel, error) @@ -41,6 +42,11 @@ const ( FROM channels AS c WHERE ` + sqlChannelValidOnly + sqlChannelMemberSelect = `SELECT m.* + FROM channel_members AS m + INNER JOIN channels AS c ON (m.rel_channel = c.id) + WHERE ` + sqlChannelValidOnly + sqlChannelDirect = `SELECT * FROM channels AS c WHERE c.type = ? @@ -57,7 +63,7 @@ const ( // subquery that filters out all channels that current user has access to as a member // or via channel type (public chans) - sqlChannelAccess = ` AND c.id IN ( + sqlChannelAccess = ` ( SELECT id FROM channels c LEFT OUTER JOIN channel_members AS m ON (c.id = m.rel_channel) @@ -121,7 +127,7 @@ func (r *channel) FindChannels(filter *types.ChannelFilter) ([]*types.Channel, e } if filter.CurrentUserID > 0 { - sql += sqlChannelAccess + sql += " AND c.id IN " + sqlChannelAccess params = append(params, filter.CurrentUserID, types.ChannelTypePublic) } @@ -132,6 +138,22 @@ func (r *channel) FindChannels(filter *types.ChannelFilter) ([]*types.Channel, e return rval, r.db().Select(&rval, sql, params...) } +// Returns member ids of all channels that user has access to +func (r *channel) FindMembers(userID uint64) (types.ChannelMemberSet, error) { + params := make([]interface{}, 0) + rval := types.ChannelMemberSet{} + + sql := sqlChannelMemberSelect + + if userID > 0 { + // scope: only channels we have access to + sql += " AND m.rel_channel IN " + sqlChannelAccess + params = append(params, userID, types.ChannelTypePublic) + } + + return rval, r.db().Select(&rval, sql, params...) +} + func (r *channel) CreateChannel(mod *types.Channel) (*types.Channel, error) { mod.ID = factory.Sonyflake.NextID() mod.CreatedAt = time.Now() diff --git a/sam/service/channel.go b/sam/service/channel.go index c97b7a852..37575e443 100644 --- a/sam/service/channel.go +++ b/sam/service/channel.go @@ -78,8 +78,18 @@ func (svc *channel) Find(filter *types.ChannelFilter) (types.ChannelSet, error) } } -func (svc *channel) preloadMembers(set types.ChannelSet) error { - // @todo implement +func (svc *channel) preloadMembers(cc types.ChannelSet) error { + var userID = auth.GetIdentityFromContext(svc.ctx).Identity() + + if mm, err := svc.channel.FindMembers(userID); err != nil { + return err + } else { + cc.Walk(func(ch *types.Channel) error { + ch.Members = mm.MembersOf(ch.ID) + return nil + }) + } + return nil } diff --git a/sam/types/channel.go b/sam/types/channel.go index 601547476..38e9bbd66 100644 --- a/sam/types/channel.go +++ b/sam/types/channel.go @@ -24,7 +24,7 @@ type ( LastMessageID uint64 `json:",omitempty" db:"rel_last_message"` Member *ChannelMember `json:"-" db:"-"` - Members []*uint64 `json:"-" db:"-"` + Members []uint64 `json:"-" db:"-"` } ChannelMember struct { @@ -49,7 +49,8 @@ type ( ChannelMembershipType string ChannelType string - ChannelSet []*Channel + ChannelSet []*Channel + ChannelMemberSet []*ChannelMember ) func (cc ChannelSet) Walk(w func(*Channel) error) (err error) { @@ -62,6 +63,28 @@ func (cc ChannelSet) Walk(w func(*Channel) error) (err error) { return } +func (mm ChannelMemberSet) Walk(w func(*ChannelMember) error) (err error) { + for i := range mm { + if err = w(mm[i]); err != nil { + return + } + } + + return +} + +func (mm ChannelMemberSet) MembersOf(channelID uint64) []uint64 { + var mmof = make([]uint64, 0) + + for i := range mm { + if mm[i].ChannelID == channelID { + mmof = append(mmof, mm[i].UserID) + } + } + + return mmof +} + const ( ChannelMembershipTypeOwner ChannelMembershipType = "owner" ChannelMembershipTypeMember = "member" diff --git a/sam/websocket/outgoing/channel.go b/sam/websocket/outgoing/channel.go index 104b03d53..4a0c644af 100644 --- a/sam/websocket/outgoing/channel.go +++ b/sam/websocket/outgoing/channel.go @@ -36,7 +36,7 @@ type ( Topic string `json:"topic"` Type string `json:"type"` LastMessageID string `json:"lastMessageID"` - Members *UserSet `json:"members,omitempty"` + Members []string `json:"members,omitempty"` } ChannelSet []*Channel diff --git a/sam/websocket/payload.go b/sam/websocket/payload.go index 9bbbdf903..9589bc2b3 100644 --- a/sam/websocket/payload.go +++ b/sam/websocket/payload.go @@ -38,6 +38,7 @@ func payloadFromChannel(ch *samTypes.Channel) *outgoing.Channel { LastMessageID: uint64toa(ch.LastMessageID), Topic: ch.Topic, Type: string(ch.Type), + Members: uint64stoa(ch.Members), } } diff --git a/sam/websocket/util.go b/sam/websocket/util.go index 3e9fce448..dbc05a500 100644 --- a/sam/websocket/util.go +++ b/sam/websocket/util.go @@ -12,6 +12,15 @@ func uint64toa(i uint64) string { return strconv.FormatUint(i, 10) } +func uint64stoa(uu []uint64) []string { + ss := make([]string, len(uu)) + for i, u := range uu { + ss[i] = uint64toa(u) + } + + return ss +} + // parseInt64 parses an string to int64 func parseInt64(s string) int64 { if s == "" {