summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api4/channel.go31
-rw-r--r--api4/channel_test.go26
-rw-r--r--app/channel.go8
-rw-r--r--model/client4.go10
-rw-r--r--store/sql_channel_store.go4
-rw-r--r--store/sql_channel_store_test.go28
-rw-r--r--store/store.go1
7 files changed, 108 insertions, 0 deletions
diff --git a/api4/channel.go b/api4/channel.go
index e02b2677c..26892bf2f 100644
--- a/api4/channel.go
+++ b/api4/channel.go
@@ -29,6 +29,7 @@ func InitChannel() {
BaseRoutes.Channel.Handle("", ApiSessionRequired(getChannel)).Methods("GET")
BaseRoutes.Channel.Handle("", ApiSessionRequired(updateChannel)).Methods("PUT")
BaseRoutes.Channel.Handle("/patch", ApiSessionRequired(patchChannel)).Methods("PUT")
+ BaseRoutes.Channel.Handle("/restore", ApiSessionRequired(restoreChannel)).Methods("POST")
BaseRoutes.Channel.Handle("", ApiSessionRequired(deleteChannel)).Methods("DELETE")
BaseRoutes.Channel.Handle("/stats", ApiSessionRequired(getChannelStats)).Methods("GET")
BaseRoutes.Channel.Handle("/pinned", ApiSessionRequired(getPinnedPosts)).Methods("GET")
@@ -180,6 +181,36 @@ func patchChannel(c *Context, w http.ResponseWriter, r *http.Request) {
}
}
+func restoreChannel(c *Context, w http.ResponseWriter, r *http.Request) {
+ c.RequireChannelId()
+ if c.Err != nil {
+ return
+ }
+
+ var channel *model.Channel
+ var err *model.AppError
+ if channel, err = app.GetChannel(c.Params.ChannelId); err != nil {
+ c.Err = err
+ return
+ }
+ teamId := channel.TeamId
+
+ if !app.SessionHasPermissionToTeam(c.Session, teamId, model.PERMISSION_MANAGE_TEAM) {
+ c.SetPermissionError(model.PERMISSION_MANAGE_TEAM)
+ return
+ }
+
+ channel, err = app.RestoreChannel(channel)
+ if err != nil {
+ c.Err = err
+ return
+ }
+
+ c.LogAudit("name=" + channel.Name)
+ w.Write([]byte(channel.ToJson()))
+
+}
+
func CanManageChannel(c *Context, channel *model.Channel) bool {
if channel.Type == model.CHANNEL_OPEN && !app.SessionHasPermissionToChannel(c.Session, channel.Id, model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES) {
c.SetPermissionError(model.PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES)
diff --git a/api4/channel_test.go b/api4/channel_test.go
index b4f08dc37..f25cbf706 100644
--- a/api4/channel_test.go
+++ b/api4/channel_test.go
@@ -1067,6 +1067,32 @@ func TestDeleteChannel(t *testing.T) {
CheckNoError(t, resp)
}
+func TestRestoreChannel(t *testing.T) {
+ th := Setup().InitBasic().InitSystemAdmin()
+ defer TearDown()
+ Client := th.Client
+
+ publicChannel1 := th.CreatePublicChannel()
+ Client.DeleteChannel(publicChannel1.Id)
+
+ privateChannel1 := th.CreatePrivateChannel()
+ Client.DeleteChannel(privateChannel1.Id)
+
+ _, resp := Client.RestoreChannel(publicChannel1.Id)
+ CheckForbiddenStatus(t, resp)
+
+ _, resp = Client.RestoreChannel(privateChannel1.Id)
+ CheckForbiddenStatus(t, resp)
+
+ th.LoginTeamAdmin()
+
+ _, resp = Client.RestoreChannel(publicChannel1.Id)
+ CheckOKStatus(t, resp)
+
+ _, resp = Client.RestoreChannel(privateChannel1.Id)
+ CheckOKStatus(t, resp)
+ }
+
func TestGetChannelByName(t *testing.T) {
th := Setup().InitBasic().InitSystemAdmin()
defer TearDown()
diff --git a/app/channel.go b/app/channel.go
index 4164b37ce..bd9acaa6d 100644
--- a/app/channel.go
+++ b/app/channel.go
@@ -285,6 +285,14 @@ func UpdateChannel(channel *model.Channel) (*model.Channel, *model.AppError) {
}
}
+func RestoreChannel(channel *model.Channel) (*model.Channel, *model.AppError) {
+ if result := <-Srv.Store.Channel().Restore(channel.Id, model.GetMillis()); result.Err != nil {
+ return nil, result.Err
+ } else {
+ return channel, nil
+ }
+}
+
func PatchChannel(channel *model.Channel, patch *model.ChannelPatch, userId string) (*model.Channel, *model.AppError) {
oldChannelDisplayName := channel.DisplayName
oldChannelHeader := channel.Header
diff --git a/model/client4.go b/model/client4.go
index 4a01a1f75..f4a247e12 100644
--- a/model/client4.go
+++ b/model/client4.go
@@ -1217,6 +1217,16 @@ func (c *Client4) PatchChannel(channelId string, patch *ChannelPatch) (*Channel,
}
}
+// RestoreChannel restores a previously deleted channel. Any missing fields are not updated.
+func (c *Client4) RestoreChannel(channelId string) (*Channel, *Response) {
+ if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/restore", ""); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ defer closeBody(r)
+ return ChannelFromJson(r.Body), BuildResponse(r)
+ }
+}
+
// CreateDirectChannel creates a direct message channel based on the two user
// ids provided.
func (c *Client4) CreateDirectChannel(userId1, userId2 string) (*Channel, *Response) {
diff --git a/store/sql_channel_store.go b/store/sql_channel_store.go
index f3619c03a..c9b6d89b8 100644
--- a/store/sql_channel_store.go
+++ b/store/sql_channel_store.go
@@ -440,6 +440,10 @@ func (s SqlChannelStore) Delete(channelId string, time int64) StoreChannel {
return s.SetDeleteAt(channelId, time, time)
}
+func (s SqlChannelStore) Restore(channelId string, time int64) StoreChannel {
+ return s.SetDeleteAt(channelId, 0, time)
+}
+
func (s SqlChannelStore) SetDeleteAt(channelId string, deleteAt int64, updateAt int64) StoreChannel {
storeChannel := make(StoreChannel, 1)
diff --git a/store/sql_channel_store_test.go b/store/sql_channel_store_test.go
index 55a263037..fc98f3f4e 100644
--- a/store/sql_channel_store_test.go
+++ b/store/sql_channel_store_test.go
@@ -364,6 +364,34 @@ func TestChannelStoreGetForPost(t *testing.T) {
}
}
+func TestSqlChannelStoreRestore(t *testing.T) {
+ Setup()
+
+ o1 := model.Channel{}
+ o1.TeamId = model.NewId()
+ o1.DisplayName = "Channel1"
+ o1.Name = "a" + model.NewId() + "b"
+ o1.Type = model.CHANNEL_OPEN
+ Must(store.Channel().Save(&o1))
+
+ if r := <-store.Channel().Delete(o1.Id, model.GetMillis()); r.Err != nil {
+ t.Fatal(r.Err)
+ }
+
+ if r := <-store.Channel().Get(o1.Id, false); r.Data.(*model.Channel).DeleteAt == 0 {
+ t.Fatal("should have been deleted")
+ }
+
+ if r := <-store.Channel().Restore(o1.Id, model.GetMillis()); r.Err != nil {
+ t.Fatal(r.Err)
+ }
+
+ if r := <-store.Channel().Get(o1.Id, false); r.Data.(*model.Channel).DeleteAt != 0 {
+ t.Fatal("should have been restored")
+ }
+
+}
+
func TestChannelStoreDelete(t *testing.T) {
Setup()
diff --git a/store/store.go b/store/store.go
index bb1b8f197..9916bfcd7 100644
--- a/store/store.go
+++ b/store/store.go
@@ -97,6 +97,7 @@ type ChannelStore interface {
InvalidateChannelByName(teamId, name string)
GetFromMaster(id string) StoreChannel
Delete(channelId string, time int64) StoreChannel
+ Restore(channelId string, time int64) StoreChannel
SetDeleteAt(channelId string, deleteAt int64, updateAt int64) StoreChannel
PermanentDeleteByTeam(teamId string) StoreChannel
PermanentDelete(channelId string) StoreChannel