make cli team / channel delete operations also delete webhooks and slash commands (#7028)
Этот коммит содержится в:
коммит произвёл
Harrison Healey
родитель
0f786a42d3
Коммит
72f61ab96a
@@ -1184,6 +1184,14 @@ func PermanentDeleteChannel(channel *model.Channel) *model.AppError {
|
|||||||
return result.Err
|
return result.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if result := <-Srv.Store.Webhook().PermanentDeleteIncomingByChannel(channel.Id); result.Err != nil {
|
||||||
|
return result.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
if result := <-Srv.Store.Webhook().PermanentDeleteOutgoingByChannel(channel.Id); result.Err != nil {
|
||||||
|
return result.Err
|
||||||
|
}
|
||||||
|
|
||||||
if result := <-Srv.Store.Channel().PermanentDelete(channel.Id); result.Err != nil {
|
if result := <-Srv.Store.Channel().PermanentDelete(channel.Id); result.Err != nil {
|
||||||
return result.Err
|
return result.Err
|
||||||
}
|
}
|
||||||
|
|||||||
66
app/channel_test.go
Обычный файл
66
app/channel_test.go
Обычный файл
@@ -0,0 +1,66 @@
|
|||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/mattermost/platform/model"
|
||||||
|
"github.com/mattermost/platform/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPermanentDeleteChannel(t *testing.T) {
|
||||||
|
th := Setup().InitBasic()
|
||||||
|
|
||||||
|
incomingWasEnabled := utils.Cfg.ServiceSettings.EnableIncomingWebhooks
|
||||||
|
outgoingWasEnabled := utils.Cfg.ServiceSettings.EnableOutgoingWebhooks
|
||||||
|
utils.Cfg.ServiceSettings.EnableIncomingWebhooks = true
|
||||||
|
utils.Cfg.ServiceSettings.EnableOutgoingWebhooks = true
|
||||||
|
defer func() {
|
||||||
|
utils.Cfg.ServiceSettings.EnableIncomingWebhooks = incomingWasEnabled
|
||||||
|
utils.Cfg.ServiceSettings.EnableOutgoingWebhooks = outgoingWasEnabled
|
||||||
|
}()
|
||||||
|
|
||||||
|
channel, err := CreateChannel(&model.Channel{DisplayName: "deletion-test", Name: "deletion-test", Type: model.CHANNEL_OPEN, TeamId: th.BasicTeam.Id}, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
PermanentDeleteChannel(channel)
|
||||||
|
}()
|
||||||
|
|
||||||
|
incoming, err := CreateIncomingWebhookForChannel(th.BasicUser.Id, channel, &model.IncomingWebhook{ChannelId: channel.Id})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
defer DeleteIncomingWebhook(incoming.Id)
|
||||||
|
|
||||||
|
if incoming, err = GetIncomingWebhook(incoming.Id); incoming == nil || err != nil {
|
||||||
|
t.Fatal("unable to get new incoming webhook")
|
||||||
|
}
|
||||||
|
|
||||||
|
outgoing, err := CreateOutgoingWebhook(&model.OutgoingWebhook{
|
||||||
|
ChannelId: channel.Id,
|
||||||
|
TeamId: channel.TeamId,
|
||||||
|
CreatorId: th.BasicUser.Id,
|
||||||
|
CallbackURLs: []string{"http://foo"},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
defer DeleteOutgoingWebhook(outgoing.Id)
|
||||||
|
|
||||||
|
if outgoing, err = GetOutgoingWebhook(outgoing.Id); outgoing == nil || err != nil {
|
||||||
|
t.Fatal("unable to get new outgoing webhook")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := PermanentDeleteChannel(channel); err != nil {
|
||||||
|
t.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if incoming, err = GetIncomingWebhook(incoming.Id); incoming != nil || err == nil {
|
||||||
|
t.Error("incoming webhook wasn't deleted")
|
||||||
|
}
|
||||||
|
|
||||||
|
if outgoing, err = GetOutgoingWebhook(outgoing.Id); outgoing != nil || err == nil {
|
||||||
|
t.Error("outgoing webhook wasn't deleted")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -638,7 +638,7 @@ func InviteNewUsersToTeam(emailList []string, teamId, senderId string) *model.Ap
|
|||||||
var invalidEmailList []string
|
var invalidEmailList []string
|
||||||
|
|
||||||
for _, email := range emailList {
|
for _, email := range emailList {
|
||||||
if ! isTeamEmailAddressAllowed(email) {
|
if !isTeamEmailAddressAllowed(email) {
|
||||||
invalidEmailList = append(invalidEmailList, email)
|
invalidEmailList = append(invalidEmailList, email)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -747,6 +747,10 @@ func PermanentDeleteTeam(team *model.Team) *model.AppError {
|
|||||||
return result.Err
|
return result.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if result := <-Srv.Store.Command().PermanentDeleteByTeam(team.Id); result.Err != nil {
|
||||||
|
return result.Err
|
||||||
|
}
|
||||||
|
|
||||||
if result := <-Srv.Store.Team().PermanentDelete(team.Id); result.Err != nil {
|
if result := <-Srv.Store.Team().PermanentDelete(team.Id); result.Err != nil {
|
||||||
return result.Err
|
return result.Err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,3 +112,44 @@ func TestAddUserToTeamByTeamId(t *testing.T) {
|
|||||||
t.Fatal("Should add user to the team")
|
t.Fatal("Should add user to the team")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPermanentDeleteTeam(t *testing.T) {
|
||||||
|
th := Setup().InitBasic()
|
||||||
|
|
||||||
|
team, err := CreateTeam(&model.Team{
|
||||||
|
DisplayName: "deletion-test",
|
||||||
|
Name: "deletion-test",
|
||||||
|
Email: "foo@foo.com",
|
||||||
|
Type: model.TEAM_OPEN,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
PermanentDeleteTeam(team)
|
||||||
|
}()
|
||||||
|
|
||||||
|
command, err := CreateCommand(&model.Command{
|
||||||
|
CreatorId: th.BasicUser.Id,
|
||||||
|
TeamId: team.Id,
|
||||||
|
Trigger: "foo",
|
||||||
|
URL: "http://foo",
|
||||||
|
Method: model.COMMAND_METHOD_POST,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
defer DeleteCommand(command.Id)
|
||||||
|
|
||||||
|
if command, err = GetCommand(command.Id); command == nil || err != nil {
|
||||||
|
t.Fatal("unable to get new command")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := PermanentDeleteTeam(team); err != nil {
|
||||||
|
t.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if command, err = GetCommand(command.Id); command != nil || err == nil {
|
||||||
|
t.Fatal("command wasn't deleted")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -6251,10 +6251,18 @@
|
|||||||
"id": "store.sql_webhooks.permanent_delete_incoming_by_user.app_error",
|
"id": "store.sql_webhooks.permanent_delete_incoming_by_user.app_error",
|
||||||
"translation": "We couldn't delete the webhook"
|
"translation": "We couldn't delete the webhook"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "store.sql_webhooks.permanent_delete_incoming_by_channel.app_error",
|
||||||
|
"translation": "We couldn't delete the webhook"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "store.sql_webhooks.permanent_delete_outgoing_by_user.app_error",
|
"id": "store.sql_webhooks.permanent_delete_outgoing_by_user.app_error",
|
||||||
"translation": "We couldn't delete the webhook"
|
"translation": "We couldn't delete the webhook"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "store.sql_webhooks.permanent_delete_outgoing_by_channel.app_error",
|
||||||
|
"translation": "We couldn't delete the webhook"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "store.sql_webhooks.save_incoming.app_error",
|
"id": "store.sql_webhooks.save_incoming.app_error",
|
||||||
"translation": "We couldn't save the IncomingWebhook"
|
"translation": "We couldn't save the IncomingWebhook"
|
||||||
|
|||||||
@@ -134,6 +134,24 @@ func (s SqlCommandStore) Delete(commandId string, time int64) StoreChannel {
|
|||||||
return storeChannel
|
return storeChannel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s SqlCommandStore) PermanentDeleteByTeam(teamId string) StoreChannel {
|
||||||
|
storeChannel := make(StoreChannel, 1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
result := StoreResult{}
|
||||||
|
|
||||||
|
_, err := s.GetMaster().Exec("DELETE FROM Commands WHERE TeamId = :TeamId", map[string]interface{}{"TeamId": teamId})
|
||||||
|
if err != nil {
|
||||||
|
result.Err = model.NewLocAppError("SqlCommandStore.DeleteByTeam", "store.sql_command.save.delete_perm.app_error", nil, "id="+teamId+", err="+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
storeChannel <- result
|
||||||
|
close(storeChannel)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return storeChannel
|
||||||
|
}
|
||||||
|
|
||||||
func (s SqlCommandStore) PermanentDeleteByUser(userId string) StoreChannel {
|
func (s SqlCommandStore) PermanentDeleteByUser(userId string) StoreChannel {
|
||||||
storeChannel := make(StoreChannel, 1)
|
storeChannel := make(StoreChannel, 1)
|
||||||
|
|
||||||
|
|||||||
@@ -111,6 +111,36 @@ func TestCommandStoreDelete(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCommandStoreDeleteByTeam(t *testing.T) {
|
||||||
|
Setup()
|
||||||
|
|
||||||
|
o1 := &model.Command{}
|
||||||
|
o1.CreatorId = model.NewId()
|
||||||
|
o1.Method = model.COMMAND_METHOD_POST
|
||||||
|
o1.TeamId = model.NewId()
|
||||||
|
o1.URL = "http://nowhere.com/"
|
||||||
|
o1.Trigger = "trigger"
|
||||||
|
|
||||||
|
o1 = (<-store.Command().Save(o1)).Data.(*model.Command)
|
||||||
|
|
||||||
|
if r1 := <-store.Command().Get(o1.Id); r1.Err != nil {
|
||||||
|
t.Fatal(r1.Err)
|
||||||
|
} else {
|
||||||
|
if r1.Data.(*model.Command).CreateAt != o1.CreateAt {
|
||||||
|
t.Fatal("invalid returned command")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r2 := <-store.Command().PermanentDeleteByTeam(o1.TeamId); r2.Err != nil {
|
||||||
|
t.Fatal(r2.Err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r3 := (<-store.Command().Get(o1.Id)); r3.Err == nil {
|
||||||
|
t.Log(r3.Data)
|
||||||
|
t.Fatal("Missing id should have failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCommandStoreDeleteByUser(t *testing.T) {
|
func TestCommandStoreDeleteByUser(t *testing.T) {
|
||||||
Setup()
|
Setup()
|
||||||
|
|
||||||
|
|||||||
@@ -186,6 +186,8 @@ func (s SqlWebhookStore) DeleteIncoming(webhookId string, time int64) StoreChann
|
|||||||
result.Err = model.NewLocAppError("SqlWebhookStore.DeleteIncoming", "store.sql_webhooks.delete_incoming.app_error", nil, "id="+webhookId+", err="+err.Error())
|
result.Err = model.NewLocAppError("SqlWebhookStore.DeleteIncoming", "store.sql_webhooks.delete_incoming.app_error", nil, "id="+webhookId+", err="+err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.InvalidateWebhookCache(webhookId)
|
||||||
|
|
||||||
storeChannel <- result
|
storeChannel <- result
|
||||||
close(storeChannel)
|
close(storeChannel)
|
||||||
}()
|
}()
|
||||||
@@ -204,6 +206,28 @@ func (s SqlWebhookStore) PermanentDeleteIncomingByUser(userId string) StoreChann
|
|||||||
result.Err = model.NewLocAppError("SqlWebhookStore.DeleteIncomingByUser", "store.sql_webhooks.permanent_delete_incoming_by_user.app_error", nil, "id="+userId+", err="+err.Error())
|
result.Err = model.NewLocAppError("SqlWebhookStore.DeleteIncomingByUser", "store.sql_webhooks.permanent_delete_incoming_by_user.app_error", nil, "id="+userId+", err="+err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ClearWebhookCaches()
|
||||||
|
|
||||||
|
storeChannel <- result
|
||||||
|
close(storeChannel)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return storeChannel
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SqlWebhookStore) PermanentDeleteIncomingByChannel(channelId string) StoreChannel {
|
||||||
|
storeChannel := make(StoreChannel, 1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
result := StoreResult{}
|
||||||
|
|
||||||
|
_, err := s.GetMaster().Exec("DELETE FROM IncomingWebhooks WHERE ChannelId = :ChannelId", map[string]interface{}{"ChannelId": channelId})
|
||||||
|
if err != nil {
|
||||||
|
result.Err = model.NewLocAppError("SqlWebhookStore.DeleteIncomingByChannel", "store.sql_webhooks.permanent_delete_incoming_by_channel.app_error", nil, "id="+channelId+", err="+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearWebhookCaches()
|
||||||
|
|
||||||
storeChannel <- result
|
storeChannel <- result
|
||||||
close(storeChannel)
|
close(storeChannel)
|
||||||
}()
|
}()
|
||||||
@@ -442,6 +466,26 @@ func (s SqlWebhookStore) PermanentDeleteOutgoingByUser(userId string) StoreChann
|
|||||||
return storeChannel
|
return storeChannel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s SqlWebhookStore) PermanentDeleteOutgoingByChannel(channelId string) StoreChannel {
|
||||||
|
storeChannel := make(StoreChannel, 1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
result := StoreResult{}
|
||||||
|
|
||||||
|
_, err := s.GetMaster().Exec("DELETE FROM OutgoingWebhooks WHERE ChannelId = :ChannelId", map[string]interface{}{"ChannelId": channelId})
|
||||||
|
if err != nil {
|
||||||
|
result.Err = model.NewLocAppError("SqlWebhookStore.DeleteOutgoingByChannel", "store.sql_webhooks.permanent_delete_outgoing_by_channel.app_error", nil, "id="+channelId+", err="+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearWebhookCaches()
|
||||||
|
|
||||||
|
storeChannel <- result
|
||||||
|
close(storeChannel)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return storeChannel
|
||||||
|
}
|
||||||
|
|
||||||
func (s SqlWebhookStore) UpdateOutgoing(hook *model.OutgoingWebhook) StoreChannel {
|
func (s SqlWebhookStore) UpdateOutgoing(hook *model.OutgoingWebhook) StoreChannel {
|
||||||
storeChannel := make(StoreChannel, 1)
|
storeChannel := make(StoreChannel, 1)
|
||||||
|
|
||||||
|
|||||||
@@ -157,7 +157,29 @@ func TestWebhookStoreDeleteIncoming(t *testing.T) {
|
|||||||
t.Fatal(r2.Err)
|
t.Fatal(r2.Err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ClearWebhookCaches()
|
if r3 := (<-store.Webhook().GetIncoming(o1.Id, true)); r3.Err == nil {
|
||||||
|
t.Log(r3.Data)
|
||||||
|
t.Fatal("Missing id should have failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWebhookStoreDeleteIncomingByChannel(t *testing.T) {
|
||||||
|
Setup()
|
||||||
|
o1 := buildIncomingWebhook()
|
||||||
|
|
||||||
|
o1 = (<-store.Webhook().SaveIncoming(o1)).Data.(*model.IncomingWebhook)
|
||||||
|
|
||||||
|
if r1 := <-store.Webhook().GetIncoming(o1.Id, true); r1.Err != nil {
|
||||||
|
t.Fatal(r1.Err)
|
||||||
|
} else {
|
||||||
|
if r1.Data.(*model.IncomingWebhook).CreateAt != o1.CreateAt {
|
||||||
|
t.Fatal("invalid returned webhook")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r2 := <-store.Webhook().PermanentDeleteIncomingByChannel(o1.ChannelId); r2.Err != nil {
|
||||||
|
t.Fatal(r2.Err)
|
||||||
|
}
|
||||||
|
|
||||||
if r3 := (<-store.Webhook().GetIncoming(o1.Id, true)); r3.Err == nil {
|
if r3 := (<-store.Webhook().GetIncoming(o1.Id, true)); r3.Err == nil {
|
||||||
t.Log(r3.Data)
|
t.Log(r3.Data)
|
||||||
@@ -183,8 +205,6 @@ func TestWebhookStoreDeleteIncomingByUser(t *testing.T) {
|
|||||||
t.Fatal(r2.Err)
|
t.Fatal(r2.Err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ClearWebhookCaches()
|
|
||||||
|
|
||||||
if r3 := (<-store.Webhook().GetIncoming(o1.Id, true)); r3.Err == nil {
|
if r3 := (<-store.Webhook().GetIncoming(o1.Id, true)); r3.Err == nil {
|
||||||
t.Log(r3.Data)
|
t.Log(r3.Data)
|
||||||
t.Fatal("Missing id should have failed")
|
t.Fatal("Missing id should have failed")
|
||||||
@@ -380,6 +400,35 @@ func TestWebhookStoreDeleteOutgoing(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestWebhookStoreDeleteOutgoingByChannel(t *testing.T) {
|
||||||
|
Setup()
|
||||||
|
|
||||||
|
o1 := &model.OutgoingWebhook{}
|
||||||
|
o1.ChannelId = model.NewId()
|
||||||
|
o1.CreatorId = model.NewId()
|
||||||
|
o1.TeamId = model.NewId()
|
||||||
|
o1.CallbackURLs = []string{"http://nowhere.com/"}
|
||||||
|
|
||||||
|
o1 = (<-store.Webhook().SaveOutgoing(o1)).Data.(*model.OutgoingWebhook)
|
||||||
|
|
||||||
|
if r1 := <-store.Webhook().GetOutgoing(o1.Id); r1.Err != nil {
|
||||||
|
t.Fatal(r1.Err)
|
||||||
|
} else {
|
||||||
|
if r1.Data.(*model.OutgoingWebhook).CreateAt != o1.CreateAt {
|
||||||
|
t.Fatal("invalid returned webhook")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r2 := <-store.Webhook().PermanentDeleteOutgoingByChannel(o1.ChannelId); r2.Err != nil {
|
||||||
|
t.Fatal(r2.Err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r3 := (<-store.Webhook().GetOutgoing(o1.Id)); r3.Err == nil {
|
||||||
|
t.Log(r3.Data)
|
||||||
|
t.Fatal("Missing id should have failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestWebhookStoreDeleteOutgoingByUser(t *testing.T) {
|
func TestWebhookStoreDeleteOutgoingByUser(t *testing.T) {
|
||||||
Setup()
|
Setup()
|
||||||
|
|
||||||
|
|||||||
@@ -296,6 +296,7 @@ type WebhookStore interface {
|
|||||||
UpdateIncoming(webhook *model.IncomingWebhook) StoreChannel
|
UpdateIncoming(webhook *model.IncomingWebhook) StoreChannel
|
||||||
GetIncomingByChannel(channelId string) StoreChannel
|
GetIncomingByChannel(channelId string) StoreChannel
|
||||||
DeleteIncoming(webhookId string, time int64) StoreChannel
|
DeleteIncoming(webhookId string, time int64) StoreChannel
|
||||||
|
PermanentDeleteIncomingByChannel(channelId string) StoreChannel
|
||||||
PermanentDeleteIncomingByUser(userId string) StoreChannel
|
PermanentDeleteIncomingByUser(userId string) StoreChannel
|
||||||
|
|
||||||
SaveOutgoing(webhook *model.OutgoingWebhook) StoreChannel
|
SaveOutgoing(webhook *model.OutgoingWebhook) StoreChannel
|
||||||
@@ -304,6 +305,7 @@ type WebhookStore interface {
|
|||||||
GetOutgoingByChannel(channelId string, offset, limit int) StoreChannel
|
GetOutgoingByChannel(channelId string, offset, limit int) StoreChannel
|
||||||
GetOutgoingByTeam(teamId string, offset, limit int) StoreChannel
|
GetOutgoingByTeam(teamId string, offset, limit int) StoreChannel
|
||||||
DeleteOutgoing(webhookId string, time int64) StoreChannel
|
DeleteOutgoing(webhookId string, time int64) StoreChannel
|
||||||
|
PermanentDeleteOutgoingByChannel(channelId string) StoreChannel
|
||||||
PermanentDeleteOutgoingByUser(userId string) StoreChannel
|
PermanentDeleteOutgoingByUser(userId string) StoreChannel
|
||||||
UpdateOutgoing(hook *model.OutgoingWebhook) StoreChannel
|
UpdateOutgoing(hook *model.OutgoingWebhook) StoreChannel
|
||||||
|
|
||||||
@@ -317,6 +319,7 @@ type CommandStore interface {
|
|||||||
Get(id string) StoreChannel
|
Get(id string) StoreChannel
|
||||||
GetByTeam(teamId string) StoreChannel
|
GetByTeam(teamId string) StoreChannel
|
||||||
Delete(commandId string, time int64) StoreChannel
|
Delete(commandId string, time int64) StoreChannel
|
||||||
|
PermanentDeleteByTeam(teamId string) StoreChannel
|
||||||
PermanentDeleteByUser(userId string) StoreChannel
|
PermanentDeleteByUser(userId string) StoreChannel
|
||||||
Update(hook *model.Command) StoreChannel
|
Update(hook *model.Command) StoreChannel
|
||||||
AnalyticsCommandCount(teamId string) StoreChannel
|
AnalyticsCommandCount(teamId string) StoreChannel
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user