3
0

Redone channel (un)deleting/(un)archiving

This commit is contained in:
Denis Arh
2018-10-31 08:36:09 +01:00
parent a14980bb5e
commit 7ac8b9b5f7
18 changed files with 235 additions and 186 deletions
-4
View File
@@ -29,10 +29,6 @@ type (
Type *string `json:"type"`
}
ChannelDelete struct {
ChannelID string `json:"id"`
}
// ChannelActivity is sent from the client when there is an activity on the channel...
ChannelActivity struct {
ChannelID uint64 `json:"ID,string"`
-1
View File
@@ -8,7 +8,6 @@ type Payload struct {
*ChannelCreate `json:"createChannel"`
*ChannelUpdate `json:"updateChannel"`
*ChannelDelete `json:"deleteChannel"`
*ChannelViewRecord `json:"recordChannelView"`
+15 -15
View File
@@ -265,9 +265,23 @@ A channel is a representation of a sequence of messages. It has meta data like c
| name | string | POST | Name of Channel | N/A | NO |
| topic | string | POST | Subject of Channel | N/A | NO |
| type | string | POST | Channel type | N/A | NO |
| archive | bool | POST | Request channel to be archived or unarchived | N/A | NO |
| organisationID | uint64 | POST | Move channel to different organisation | N/A | NO |
## Update channel state
#### Method
| URI | Protocol | Method | Authentication |
| --- | -------- | ------ | -------------- |
| `/channels/{channelID}/state` | HTTP/S | PUT | Client ID, Session ID |
#### Request parameters
| Parameter | Type | Method | Description | Default | Required? |
| --------- | ---- | ------ | ----------- | ------- | --------- |
| channelID | uint64 | PATH | Channel ID | N/A | YES |
| state | string | POST | Valid values: delete, restore, archive, unarchive | N/A | YES |
## Read channel details
#### Method
@@ -282,20 +296,6 @@ A channel is a representation of a sequence of messages. It has meta data like c
| --------- | ---- | ------ | ----------- | ------- | --------- |
| channelID | uint64 | PATH | Channel ID | N/A | YES |
## Remove channel
#### Method
| URI | Protocol | Method | Authentication |
| --- | -------- | ------ | -------------- |
| `/channels/{channelID}` | HTTP/S | DELETE | Client ID, Session ID |
#### Request parameters
| Parameter | Type | Method | Description | Default | Required? |
| --------- | ---- | ------ | ----------- | ------- | --------- |
| channelID | uint64 | PATH | Channel ID | N/A | YES |
## List channel members
#### Method
+15 -13
View File
@@ -221,7 +221,7 @@
}
},
{
"name": "edit",
"name": "update",
"method": "PUT",
"path": "/{channelID}",
"title": "Update channel details",
@@ -233,11 +233,24 @@
{ "type": "string", "name": "name", "required": false, "title": "Name of Channel" },
{ "type": "string", "name": "topic", "required": false, "title": "Subject of Channel" },
{ "type": "string", "name": "type", "required": false, "title": "Channel type" },
{ "type": "bool", "name": "archive", "required": false, "title": "Request channel to be archived or unarchived" },
{ "type": "uint64", "name": "organisationID", "required": false, "title": "Move channel to different organisation" }
]
}
},
{
"name": "state",
"method": "PUT",
"path": "/{channelID}/state",
"title": "Update channel state",
"parameters": {
"path": [
{ "type": "uint64", "name": "channelID", "required": true, "title": "Channel ID" }
],
"post": [
{ "type": "string", "name": "state", "required": true, "title": "Valid values: delete, undelete, archive, unarchive" }
]
}
},
{
"name": "read",
"method": "GET",
@@ -249,17 +262,6 @@
]
}
},
{
"name": "delete",
"method": "DELETE",
"path": "/{channelID}",
"title": "Remove channel",
"parameters": {
"path": [
{ "type": "uint64", "name": "channelID", "required": true, "title": "Channel ID" }
]
}
},
{
"name": "members",
"method": "GET",
+16 -14
View File
@@ -63,7 +63,7 @@
}
},
{
"Name": "edit",
"Name": "update",
"Method": "PUT",
"Title": "Update channel details",
"Path": "/{channelID}",
@@ -95,12 +95,6 @@
"title": "Channel type",
"type": "string"
},
{
"name": "archive",
"required": false,
"title": "Request channel to be archived or unarchived",
"type": "bool"
},
{
"name": "organisationID",
"required": false,
@@ -111,10 +105,10 @@
}
},
{
"Name": "read",
"Method": "GET",
"Title": "Read channel details",
"Path": "/{channelID}",
"Name": "state",
"Method": "PUT",
"Title": "Update channel state",
"Path": "/{channelID}/state",
"Parameters": {
"path": [
{
@@ -123,13 +117,21 @@
"title": "Channel ID",
"type": "uint64"
}
],
"post": [
{
"name": "state",
"required": true,
"title": "Valid values: delete, restore, archive, unarchive",
"type": "string"
}
]
}
},
{
"Name": "delete",
"Method": "DELETE",
"Title": "Remove channel",
"Name": "read",
"Method": "GET",
"Title": "Read channel details",
"Path": "/{channelID}",
"Parameters": {
"path": [
+17 -8
View File
@@ -24,6 +24,7 @@ type (
ArchiveChannelByID(id uint64) error
UnarchiveChannelByID(id uint64) error
DeleteChannelByID(id uint64) error
UndeleteChannelByID(id uint64) error
}
channel struct {
@@ -32,13 +33,22 @@ type (
)
const (
sqlChannelValidOnly = ` true
AND c.archived_at IS NULL
AND c.deleted_at IS NULL`
sqlChannelColumns = " id," +
"name, " +
"meta, " +
"created_at, " +
"updated_at, " +
"archived_at, " +
"deleted_at, " +
"rel_organisation, " +
"rel_creator, " +
"type , " +
"rel_last_message, " +
"topic"
sqlChannelSelect = `SELECT *
sqlChannelSelect = `SELECT ` + sqlChannelColumns + `
FROM channels AS c
WHERE ` + sqlChannelValidOnly
WHERE true `
sqlChannelGroupByMemberSet = sqlChannelSelect + ` AND c.type = ? AND c.id IN (
SELECT rel_channel
@@ -49,7 +59,7 @@ const (
)`
// subquery that filters out all channels that current user has access to as a member
// or via channel type (public chans)
// or via channel type (public channels)
sqlChannelAccess = ` (
SELECT id
FROM channels c
@@ -115,7 +125,6 @@ func (r *channel) FindChannels(filter *types.ChannelFilter) ([]*types.Channel, e
if filter.CurrentUserID > 0 {
sql += " AND c.id IN " + sqlChannelAccess
params = append(params, filter.CurrentUserID, types.ChannelTypePublic)
}
}
@@ -162,6 +171,6 @@ func (r *channel) DeleteChannelByID(id uint64) error {
return r.updateColumnByID("channels", "deleted_at", time.Now(), id)
}
func (r *channel) RecoverChannelByID(id uint64) error {
func (r *channel) UndeleteChannelByID(id uint64) error {
return r.updateColumnByID("channels", "deleted_at", nil, id)
}
+2 -9
View File
@@ -27,9 +27,6 @@ type (
)
const (
// Copy definitions to make it more obvious that we're reusing channel-scope sql
sqlChannelMemberChannelValidOnly = sqlChannelValidOnly
// Copy definitions to make it more obvious that we're reusing channel-scope sql
sqlChannelMemberChannelAccess = sqlChannelAccess
@@ -37,12 +34,8 @@ const (
sqlChannelMemberSelect = `SELECT m.*
FROM channel_members AS m
INNER JOIN channels AS c ON (m.rel_channel = c.id)
WHERE ` + sqlChannelMemberChannelValidOnly
// Selects all user's memberships
sqlChannelMemberships = `SELECT *
FROM channel_members AS cm
WHERE true`
WHERE c.archived_at IS NULL
AND c.deleted_at IS NULL`
)
// ChannelMember creates new instance of channel member repository
+5
View File
@@ -65,5 +65,10 @@ func TestChannel(t *testing.T) {
err = rpo.DeleteChannelByID(chn.ID)
assert(t, err == nil, "DeleteChannelByID error: %v", err)
}
{
err = rpo.UndeleteChannelByID(chn.ID)
assert(t, err == nil, "UndeleteChannelByID error: %v", err)
}
}
}
+14 -4
View File
@@ -41,7 +41,7 @@ func (ctrl *Channel) Create(ctx context.Context, r *request.ChannelCreate) (inte
return ctrl.wrap(ctrl.svc.ch.With(ctx).Create(channel))
}
func (ctrl *Channel) Edit(ctx context.Context, r *request.ChannelEdit) (interface{}, error) {
func (ctrl *Channel) Update(ctx context.Context, r *request.ChannelUpdate) (interface{}, error) {
channel := &types.Channel{
ID: r.ChannelID,
Name: r.Name,
@@ -50,11 +50,21 @@ func (ctrl *Channel) Edit(ctx context.Context, r *request.ChannelEdit) (interfac
}
return ctrl.wrap(ctrl.svc.ch.With(ctx).Update(channel))
}
func (ctrl *Channel) Delete(ctx context.Context, r *request.ChannelDelete) (interface{}, error) {
return nil, ctrl.svc.ch.With(ctx).Delete(r.ChannelID)
func (ctrl *Channel) State(ctx context.Context, r *request.ChannelState) (interface{}, error) {
switch r.State {
case "delete":
return ctrl.wrap(ctrl.svc.ch.With(ctx).Delete(r.ChannelID))
case "undelete":
return ctrl.wrap(ctrl.svc.ch.With(ctx).Undelete(r.ChannelID))
case "archive":
return ctrl.wrap(ctrl.svc.ch.With(ctx).Archive(r.ChannelID))
case "unarchive":
return ctrl.wrap(ctrl.svc.ch.With(ctx).Unarchive(r.ChannelID))
}
return nil, nil
}
func (ctrl *Channel) Read(ctx context.Context, r *request.ChannelRead) (interface{}, error) {
+16 -16
View File
@@ -29,9 +29,9 @@ import (
type ChannelAPI interface {
List(context.Context, *request.ChannelList) (interface{}, error)
Create(context.Context, *request.ChannelCreate) (interface{}, error)
Edit(context.Context, *request.ChannelEdit) (interface{}, error)
Update(context.Context, *request.ChannelUpdate) (interface{}, error)
State(context.Context, *request.ChannelState) (interface{}, error)
Read(context.Context, *request.ChannelRead) (interface{}, error)
Delete(context.Context, *request.ChannelDelete) (interface{}, error)
Members(context.Context, *request.ChannelMembers) (interface{}, error)
Join(context.Context, *request.ChannelJoin) (interface{}, error)
Part(context.Context, *request.ChannelPart) (interface{}, error)
@@ -43,9 +43,9 @@ type ChannelAPI interface {
type Channel struct {
List func(http.ResponseWriter, *http.Request)
Create func(http.ResponseWriter, *http.Request)
Edit func(http.ResponseWriter, *http.Request)
Update func(http.ResponseWriter, *http.Request)
State func(http.ResponseWriter, *http.Request)
Read func(http.ResponseWriter, *http.Request)
Delete func(http.ResponseWriter, *http.Request)
Members func(http.ResponseWriter, *http.Request)
Join func(http.ResponseWriter, *http.Request)
Part func(http.ResponseWriter, *http.Request)
@@ -69,11 +69,18 @@ func NewChannel(ch ChannelAPI) *Channel {
return ch.Create(r.Context(), params)
})
},
Edit: func(w http.ResponseWriter, r *http.Request) {
Update: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewChannelEdit()
params := request.NewChannelUpdate()
resputil.JSON(w, params.Fill(r), func() (interface{}, error) {
return ch.Edit(r.Context(), params)
return ch.Update(r.Context(), params)
})
},
State: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewChannelState()
resputil.JSON(w, params.Fill(r), func() (interface{}, error) {
return ch.State(r.Context(), params)
})
},
Read: func(w http.ResponseWriter, r *http.Request) {
@@ -83,13 +90,6 @@ func NewChannel(ch ChannelAPI) *Channel {
return ch.Read(r.Context(), params)
})
},
Delete: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewChannelDelete()
resputil.JSON(w, params.Fill(r), func() (interface{}, error) {
return ch.Delete(r.Context(), params)
})
},
Members: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewChannelMembers()
@@ -134,9 +134,9 @@ func (ch *Channel) MountRoutes(r chi.Router, middlewares ...func(http.Handler) h
r.Route("/channels", func(r chi.Router) {
r.Get("/", ch.List)
r.Post("/", ch.Create)
r.Put("/{channelID}", ch.Edit)
r.Put("/{channelID}", ch.Update)
r.Put("/{channelID}/state", ch.State)
r.Get("/{channelID}", ch.Read)
r.Delete("/{channelID}", ch.Delete)
r.Get("/{channelID}/members", ch.Members)
r.Put("/{channelID}/members/{userID}", ch.Join)
r.Delete("/{channelID}/members/{userID}", ch.Part)
+54 -54
View File
@@ -133,21 +133,20 @@ func (c *ChannelCreate) Fill(r *http.Request) (err error) {
var _ RequestFiller = NewChannelCreate()
// Channel edit request parameters
type ChannelEdit struct {
// Channel update request parameters
type ChannelUpdate struct {
ChannelID uint64 `json:",string"`
Name string
Topic string
Type string
Archive bool
OrganisationID uint64 `json:",string"`
}
func NewChannelEdit() *ChannelEdit {
return &ChannelEdit{}
func NewChannelUpdate() *ChannelUpdate {
return &ChannelUpdate{}
}
func (c *ChannelEdit) Fill(r *http.Request) (err error) {
func (c *ChannelUpdate) Fill(r *http.Request) (err error) {
if strings.ToLower(r.Header.Get("content-type")) == "application/json" {
err = json.NewDecoder(r.Body).Decode(c)
@@ -187,10 +186,6 @@ func (c *ChannelEdit) Fill(r *http.Request) (err error) {
c.Type = val
}
if val, ok := post["archive"]; ok {
c.Archive = parseBool(val)
}
if val, ok := post["organisationID"]; ok {
c.OrganisationID = parseUInt64(val)
@@ -199,7 +194,55 @@ func (c *ChannelEdit) Fill(r *http.Request) (err error) {
return err
}
var _ RequestFiller = NewChannelEdit()
var _ RequestFiller = NewChannelUpdate()
// Channel state request parameters
type ChannelState struct {
ChannelID uint64 `json:",string"`
State string
}
func NewChannelState() *ChannelState {
return &ChannelState{}
}
func (c *ChannelState) Fill(r *http.Request) (err error) {
if strings.ToLower(r.Header.Get("content-type")) == "application/json" {
err = json.NewDecoder(r.Body).Decode(c)
switch {
case err == io.EOF:
err = nil
case err != nil:
return errors.Wrap(err, "error parsing http request body")
}
}
if err = r.ParseForm(); err != nil {
return err
}
get := map[string]string{}
post := map[string]string{}
urlQuery := r.URL.Query()
for name, param := range urlQuery {
get[name] = string(param[0])
}
postVars := r.Form
for name, param := range postVars {
post[name] = string(param[0])
}
c.ChannelID = parseUInt64(chi.URLParam(r, "channelID"))
if val, ok := post["state"]; ok {
c.State = val
}
return err
}
var _ RequestFiller = NewChannelState()
// Channel read request parameters
type ChannelRead struct {
@@ -244,49 +287,6 @@ func (c *ChannelRead) Fill(r *http.Request) (err error) {
var _ RequestFiller = NewChannelRead()
// Channel delete request parameters
type ChannelDelete struct {
ChannelID uint64 `json:",string"`
}
func NewChannelDelete() *ChannelDelete {
return &ChannelDelete{}
}
func (c *ChannelDelete) Fill(r *http.Request) (err error) {
if strings.ToLower(r.Header.Get("content-type")) == "application/json" {
err = json.NewDecoder(r.Body).Decode(c)
switch {
case err == io.EOF:
err = nil
case err != nil:
return errors.Wrap(err, "error parsing http request body")
}
}
if err = r.ParseForm(); err != nil {
return err
}
get := map[string]string{}
post := map[string]string{}
urlQuery := r.URL.Query()
for name, param := range urlQuery {
get[name] = string(param[0])
}
postVars := r.Form
for name, param := range postVars {
post[name] = string(param[0])
}
c.ChannelID = parseUInt64(chi.URLParam(r, "channelID"))
return err
}
var _ RequestFiller = NewChannelDelete()
// Channel members request parameters
type ChannelMembers struct {
ChannelID uint64 `json:",string"`
+42 -27
View File
@@ -46,9 +46,10 @@ type (
AddMember(channelID uint64, memberIDs ...uint64) (out types.ChannelMemberSet, err error)
DeleteMember(channelID uint64, memberIDs ...uint64) (err error)
Archive(ID uint64) error
Unarchive(ID uint64) error
Delete(ID uint64) error
Archive(ID uint64) (*types.Channel, error)
Unarchive(ID uint64) (*types.Channel, error)
Delete(ID uint64) (*types.Channel, error)
Undelete(ID uint64) (*types.Channel, error)
RecordView(userID, channelID, lastMessageID uint64) error
}
@@ -88,12 +89,14 @@ func (svc *channel) With(ctx context.Context) ChannelService {
}
}
func (svc *channel) FindByID(id uint64) (ch *types.Channel, err error) {
ch, err = svc.channel.FindChannelByID(id)
func (svc *channel) FindByID(ID uint64) (ch *types.Channel, err error) {
ch, err = svc.channel.FindChannelByID(ID)
if err != nil {
return
}
// @todo [SECURITY] check if user can access this channel
// @todo [SECURITY] check if user can access inactive channels
// if !svc.sec.ch.CanRead(ch) {
// return nil, errors.New("Not allowed to access channel")
// }
@@ -111,6 +114,11 @@ func (svc *channel) Find(filter *types.ChannelFilter) (cc types.ChannelSet, err
return
}
// @todo [SECURITY] check if user can access inactive channels
cc, _ = cc.Filter(func(i *types.Channel) (b bool, e error) {
return true || i.DeletedAt == nil, nil
})
return
})
}
@@ -425,19 +433,18 @@ func (svc *channel) Update(in *types.Channel) (ch *types.Channel, err error) {
return
}
svc.flushSystemMessages()
_ = svc.flushSystemMessages()
return svc.sendChannelEvent(ch)
})
}
func (svc *channel) Delete(id uint64) error {
return svc.db.Transaction(func() (err error) {
func (svc *channel) Delete(ID uint64) (ch *types.Channel, err error) {
return ch, svc.db.Transaction(func() (err error) {
var userID = repository.Identity(svc.ctx)
var ch *types.Channel
// @todo [SECURITY] can user access this channel?
if ch, err = svc.channel.FindChannelByID(id); err != nil {
if ch, err = svc.channel.FindChannelByID(ID); err != nil {
return
}
@@ -452,8 +459,11 @@ func (svc *channel) Delete(id uint64) error {
svc.scheduleSystemMessage(ch, "<@%d> deleted this channel", userID)
if err = svc.channel.DeleteChannelByID(id); err != nil {
if err = svc.channel.DeleteChannelByID(ID); err != nil {
return
} else {
// Set deletedAt timestamp so that our clients can react properly...
ch.DeletedAt = timeNowPtr()
}
_ = svc.sendChannelEvent(ch)
@@ -462,13 +472,12 @@ func (svc *channel) Delete(id uint64) error {
})
}
func (svc *channel) Recover(id uint64) error {
return svc.db.Transaction(func() (err error) {
func (svc *channel) Undelete(ID uint64) (ch *types.Channel, err error) {
return ch, svc.db.Transaction(func() (err error) {
var userID = repository.Identity(svc.ctx)
var ch *types.Channel
// @todo [SECURITY] can user access this channel?
if ch, err = svc.channel.FindChannelByID(id); err != nil {
if ch, err = svc.channel.FindChannelByID(ID); err != nil {
return
}
@@ -478,10 +487,13 @@ func (svc *channel) Recover(id uint64) error {
return errors.New("Channel not deleted")
}
svc.scheduleSystemMessage(ch, "<@%d> recovered this channel", userID)
svc.scheduleSystemMessage(ch, "<@%d> undeleted this channel", userID)
if err = svc.channel.UnarchiveChannelByID(id); err != nil {
if err = svc.channel.UndeleteChannelByID(ID); err != nil {
return
} else {
// Remove deletedAt timestamp so that our clients can react properly...
ch.DeletedAt = nil
}
svc.flushSystemMessages()
@@ -489,14 +501,12 @@ func (svc *channel) Recover(id uint64) error {
})
}
func (svc *channel) Archive(id uint64) error {
return svc.db.Transaction(func() (err error) {
func (svc *channel) Archive(ID uint64) (ch *types.Channel, err error) {
return ch, svc.db.Transaction(func() (err error) {
var userID = repository.Identity(svc.ctx)
var ch *types.Channel
// @todo [SECURITY] can user access this channel?
if ch, err = svc.channel.FindChannelByID(id); err != nil {
if ch, err = svc.channel.FindChannelByID(ID); err != nil {
return
}
@@ -508,8 +518,11 @@ func (svc *channel) Archive(id uint64) error {
svc.scheduleSystemMessage(ch, "<@%d> archived this channel", userID)
if err = svc.channel.ArchiveChannelByID(id); err != nil {
if err = svc.channel.ArchiveChannelByID(ID); err != nil {
return
} else {
// Set archivedAt timestamp so that our clients can react properly...
ch.ArchivedAt = timeNowPtr()
}
svc.flushSystemMessages()
@@ -517,13 +530,12 @@ func (svc *channel) Archive(id uint64) error {
})
}
func (svc *channel) Unarchive(id uint64) error {
return svc.db.Transaction(func() (err error) {
func (svc *channel) Unarchive(ID uint64) (ch *types.Channel, err error) {
return ch, svc.db.Transaction(func() (err error) {
var userID = repository.Identity(svc.ctx)
var ch *types.Channel
// @todo [SECURITY] can user access this channel?
if ch, err = svc.channel.FindChannelByID(id); err != nil {
if ch, err = svc.channel.FindChannelByID(ID); err != nil {
return
}
@@ -531,6 +543,9 @@ func (svc *channel) Unarchive(id uint64) error {
if ch.ArchivedAt == nil {
return errors.New("Channel not archived")
} else {
// Unset archivedAt timestamp so that our clients can react properly...
ch.ArchivedAt = nil
}
svc.scheduleSystemMessage(ch, "<@%d> unarchived this channel", userID)
+3 -5
View File
@@ -3,7 +3,6 @@ package service
import (
"context"
"strings"
"time"
"github.com/pkg/errors"
@@ -280,12 +279,11 @@ func (svc *message) Delete(ID uint64) error {
return
}
// Set deletedAt timestamp so that our clients can react properly...
now := time.Now()
deletedMsg.DeletedAt = &now
if err = svc.cview.Dec(deletedMsg.ChannelID, deletedMsg.UserID); err != nil {
return err
} else {
// Set deletedAt timestamp so that our clients can react properly...
deletedMsg.DeletedAt = timeNowPtr()
}
return svc.sendEvent(append(bq, deletedMsg)...)
+6
View File
@@ -3,6 +3,7 @@ package service
import (
"log"
"sync"
"time"
"github.com/crusttech/crust/internal/store"
)
@@ -40,3 +41,8 @@ func Init() {
DefaultTeam = Team()
})
}
func timeNowPtr() *time.Time {
now := time.Now()
return &now
}
+28 -8
View File
@@ -17,8 +17,9 @@ type (
CreatorID uint64 `json:"creatorId" db:"rel_creator"`
OrganisationID uint64 `json:"organisationId" db:"rel_organisation"`
CreatedAt time.Time `json:"createdAt,omitempty" db:"created_at"`
UpdatedAt *time.Time `json:"updatedAt,omitempty" db:"updated_at"`
CreatedAt time.Time `json:"createdAt,omitempty" db:"created_at"`
UpdatedAt *time.Time `json:"updatedAt,omitempty" db:"updated_at"`
ArchivedAt *time.Time `json:"archivedAt,omitempty" db:"archived_at"`
DeletedAt *time.Time `json:"deletedAt,omitempty" db:"deleted_at"`
@@ -35,7 +36,8 @@ type (
// Only return channels accessible by this user
CurrentUserID uint64
IncludeMembers bool
// Do not filter out deleted channels
IncludeDeleted bool
}
ChannelType string
@@ -44,18 +46,22 @@ type (
)
// Scope returns permissions group that for this type
func (r *Channel) Scope() string {
func (c *Channel) Scope() string {
return "channel"
}
// Resource returns a RBAC resource ID for this type
func (r *Channel) Resource() string {
return fmt.Sprintf("%s:%d", r.Scope(), r.ID)
func (c *Channel) Resource() string {
return fmt.Sprintf("%s:%d", c.Scope(), c.ID)
}
// Operation returns a RBAC resource-scoped role name for an operation
func (r *Channel) Operation(name string) string {
return fmt.Sprintf("%s/%s", r.Resource(), name)
func (c *Channel) Operation(name string) string {
return fmt.Sprintf("%s/%s", c.Resource(), name)
}
func (c *Channel) IsValid() bool {
return c.ArchivedAt == nil && c.DeletedAt == nil
}
func (cc ChannelSet) Walk(w func(*Channel) error) (err error) {
@@ -68,6 +74,20 @@ func (cc ChannelSet) Walk(w func(*Channel) error) (err error) {
return
}
func (cc ChannelSet) Filter(f func(*Channel) (bool, error)) (out ChannelSet, err error) {
var ok bool
out = ChannelSet{}
for i := range cc {
if ok, err = f(cc[i]); err != nil {
return
} else if ok {
out = append(out, cc[i])
}
}
return
}
func (cc ChannelSet) FindById(ID uint64) *Channel {
for i := range cc {
if cc[i].ID == ID {
+1 -1
View File
@@ -92,7 +92,7 @@ func (sess *Session) connected() (err error) {
}
// Push user info about all channels he has access to...
if cc, err = sess.svc.ch.With(sess.ctx).Find(&types.ChannelFilter{IncludeMembers: true}); err != nil {
if cc, err = sess.svc.ch.With(sess.ctx).Find(&types.ChannelFilter{}); err != nil {
log.Printf("Error: %v", err)
} else {
if err = sess.sendReply(payload.Channels(cc)); err != nil {
-2
View File
@@ -35,8 +35,6 @@ func (s *Session) dispatch(raw []byte) error {
return s.channelList(ctx, p.Channels)
case p.ChannelCreate != nil:
return s.channelCreate(ctx, p.ChannelCreate)
case p.ChannelDelete != nil:
return s.channelDelete(ctx, p.ChannelDelete)
case p.ChannelUpdate != nil:
return s.channelUpdate(ctx, p.ChannelUpdate)
case p.ChannelViewRecord != nil:
+1 -5
View File
@@ -45,7 +45,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 := s.svc.ch.With(ctx).Find(&types.ChannelFilter{IncludeMembers: true})
channels, err := s.svc.ch.With(ctx).Find(&types.ChannelFilter{})
if err != nil {
return err
}
@@ -80,10 +80,6 @@ func (s *Session) channelCreate(ctx context.Context, p *incoming.ChannelCreate)
return nil
}
func (s *Session) channelDelete(ctx context.Context, p *incoming.ChannelDelete) (err error) {
return s.svc.ch.With(ctx).Delete(payload.ParseUInt64(p.ChannelID))
}
func (s *Session) channelUpdate(ctx context.Context, p *incoming.ChannelUpdate) error {
ch, err := s.svc.ch.With(ctx).FindByID(payload.ParseUInt64(p.ID))
if err != nil {