Merge pull request #1149 from mattermost/plt-808
PLT-808 Fix deleting channels breaking the webhook UI
Этот коммит содержится в:
@@ -508,6 +508,8 @@ func deleteChannel(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
sc := Srv.Store.Channel().Get(id)
|
sc := Srv.Store.Channel().Get(id)
|
||||||
scm := Srv.Store.Channel().GetMember(id, c.Session.UserId)
|
scm := Srv.Store.Channel().GetMember(id, c.Session.UserId)
|
||||||
uc := Srv.Store.User().Get(c.Session.UserId)
|
uc := Srv.Store.User().Get(c.Session.UserId)
|
||||||
|
ihc := Srv.Store.Webhook().GetIncomingByChannel(id)
|
||||||
|
ohc := Srv.Store.Webhook().GetOutgoingByChannel(id)
|
||||||
|
|
||||||
if cresult := <-sc; cresult.Err != nil {
|
if cresult := <-sc; cresult.Err != nil {
|
||||||
c.Err = cresult.Err
|
c.Err = cresult.Err
|
||||||
@@ -518,10 +520,18 @@ func deleteChannel(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
} else if scmresult := <-scm; scmresult.Err != nil {
|
} else if scmresult := <-scm; scmresult.Err != nil {
|
||||||
c.Err = scmresult.Err
|
c.Err = scmresult.Err
|
||||||
return
|
return
|
||||||
|
} else if ihcresult := <-ihc; ihcresult.Err != nil {
|
||||||
|
c.Err = ihcresult.Err
|
||||||
|
return
|
||||||
|
} else if ohcresult := <-ohc; ohcresult.Err != nil {
|
||||||
|
c.Err = ohcresult.Err
|
||||||
|
return
|
||||||
} else {
|
} else {
|
||||||
channel := cresult.Data.(*model.Channel)
|
channel := cresult.Data.(*model.Channel)
|
||||||
user := uresult.Data.(*model.User)
|
user := uresult.Data.(*model.User)
|
||||||
channelMember := scmresult.Data.(model.ChannelMember)
|
channelMember := scmresult.Data.(model.ChannelMember)
|
||||||
|
incomingHooks := ihcresult.Data.([]*model.IncomingWebhook)
|
||||||
|
outgoingHooks := ohcresult.Data.([]*model.OutgoingWebhook)
|
||||||
|
|
||||||
if !c.HasPermissionsToTeam(channel.TeamId, "deleteChannel") {
|
if !c.HasPermissionsToTeam(channel.TeamId, "deleteChannel") {
|
||||||
return
|
return
|
||||||
@@ -545,6 +555,23 @@ func deleteChannel(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
now := model.GetMillis()
|
||||||
|
for _, hook := range incomingHooks {
|
||||||
|
go func() {
|
||||||
|
if result := <-Srv.Store.Webhook().DeleteIncoming(hook.Id, now); result.Err != nil {
|
||||||
|
l4g.Error("Encountered error deleting incoming webhook, id=" + hook.Id)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, hook := range outgoingHooks {
|
||||||
|
go func() {
|
||||||
|
if result := <-Srv.Store.Webhook().DeleteOutgoing(hook.Id, now); result.Err != nil {
|
||||||
|
l4g.Error("Encountered error deleting outgoing webhook, id=" + hook.Id)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
if dresult := <-Srv.Store.Channel().Delete(channel.Id, model.GetMillis()); dresult.Err != nil {
|
if dresult := <-Srv.Store.Channel().Delete(channel.Id, model.GetMillis()); dresult.Err != nil {
|
||||||
c.Err = dresult.Err
|
c.Err = dresult.Err
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -137,6 +137,27 @@ func (s SqlWebhookStore) GetIncomingByUser(userId string) StoreChannel {
|
|||||||
return storeChannel
|
return storeChannel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s SqlWebhookStore) GetIncomingByChannel(channelId string) StoreChannel {
|
||||||
|
storeChannel := make(StoreChannel)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
result := StoreResult{}
|
||||||
|
|
||||||
|
var webhooks []*model.IncomingWebhook
|
||||||
|
|
||||||
|
if _, err := s.GetReplica().Select(&webhooks, "SELECT * FROM IncomingWebhooks WHERE ChannelId = :ChannelId AND DeleteAt = 0", map[string]interface{}{"ChannelId": channelId}); err != nil {
|
||||||
|
result.Err = model.NewAppError("SqlWebhookStore.GetIncomingByChannel", "We couldn't get the webhooks", "channelId="+channelId+", err="+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Data = webhooks
|
||||||
|
|
||||||
|
storeChannel <- result
|
||||||
|
close(storeChannel)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return storeChannel
|
||||||
|
}
|
||||||
|
|
||||||
func (s SqlWebhookStore) SaveOutgoing(webhook *model.OutgoingWebhook) StoreChannel {
|
func (s SqlWebhookStore) SaveOutgoing(webhook *model.OutgoingWebhook) StoreChannel {
|
||||||
storeChannel := make(StoreChannel)
|
storeChannel := make(StoreChannel)
|
||||||
|
|
||||||
|
|||||||
@@ -150,6 +150,7 @@ type WebhookStore interface {
|
|||||||
SaveIncoming(webhook *model.IncomingWebhook) StoreChannel
|
SaveIncoming(webhook *model.IncomingWebhook) StoreChannel
|
||||||
GetIncoming(id string) StoreChannel
|
GetIncoming(id string) StoreChannel
|
||||||
GetIncomingByUser(userId string) StoreChannel
|
GetIncomingByUser(userId string) StoreChannel
|
||||||
|
GetIncomingByChannel(channelId string) StoreChannel
|
||||||
DeleteIncoming(webhookId string, time int64) StoreChannel
|
DeleteIncoming(webhookId string, time int64) StoreChannel
|
||||||
SaveOutgoing(webhook *model.OutgoingWebhook) StoreChannel
|
SaveOutgoing(webhook *model.OutgoingWebhook) StoreChannel
|
||||||
GetOutgoing(id string) StoreChannel
|
GetOutgoing(id string) StoreChannel
|
||||||
|
|||||||
@@ -96,7 +96,14 @@ export default class ManageIncomingHooks extends React.Component {
|
|||||||
const options = [];
|
const options = [];
|
||||||
channels.forEach((channel) => {
|
channels.forEach((channel) => {
|
||||||
if (channel.type !== Constants.DM_CHANNEL) {
|
if (channel.type !== Constants.DM_CHANNEL) {
|
||||||
options.push(<option value={channel.id}>{channel.name}</option>);
|
options.push(
|
||||||
|
<option
|
||||||
|
key={'incoming-hook' + channel.id}
|
||||||
|
value={channel.id}
|
||||||
|
>
|
||||||
|
{channel.display_name}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -108,26 +115,31 @@ export default class ManageIncomingHooks extends React.Component {
|
|||||||
const hooks = [];
|
const hooks = [];
|
||||||
this.state.hooks.forEach((hook) => {
|
this.state.hooks.forEach((hook) => {
|
||||||
const c = ChannelStore.get(hook.channel_id);
|
const c = ChannelStore.get(hook.channel_id);
|
||||||
hooks.push(
|
if (c) {
|
||||||
<div className='font--small'>
|
hooks.push(
|
||||||
<div className='padding-top x2 divider-light'></div>
|
<div
|
||||||
<div className='padding-top x2'>
|
key={hook.id}
|
||||||
<strong>{'URL: '}</strong><span className='word-break--all'>{Utils.getWindowLocationOrigin() + '/hooks/' + hook.id}</span>
|
className='font--small'
|
||||||
|
>
|
||||||
|
<div className='padding-top x2 divider-light'></div>
|
||||||
|
<div className='padding-top x2'>
|
||||||
|
<strong>{'URL: '}</strong><span className='word-break--all'>{Utils.getWindowLocationOrigin() + '/hooks/' + hook.id}</span>
|
||||||
|
</div>
|
||||||
|
<div className='padding-top'>
|
||||||
|
<strong>{'Channel: '}</strong>{c.display_name}
|
||||||
|
</div>
|
||||||
|
<div className='padding-top'>
|
||||||
|
<a
|
||||||
|
className={'text-danger'}
|
||||||
|
href='#'
|
||||||
|
onClick={this.removeHook.bind(this, hook.id)}
|
||||||
|
>
|
||||||
|
{'Remove'}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='padding-top'>
|
);
|
||||||
<strong>{'Channel: '}</strong>{c.name}
|
}
|
||||||
</div>
|
|
||||||
<div className='padding-top'>
|
|
||||||
<a
|
|
||||||
className={'text-danger'}
|
|
||||||
href='#'
|
|
||||||
onClick={this.removeHook.bind(this, hook.id)}
|
|
||||||
>
|
|
||||||
{'Remove'}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let displayHooks;
|
let displayHooks;
|
||||||
|
|||||||
@@ -128,21 +128,42 @@ export default class ManageOutgoingHooks extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const channels = ChannelStore.getAll();
|
const channels = ChannelStore.getAll();
|
||||||
const options = [<option value=''>{'--- Select a channel ---'}</option>];
|
const options = [];
|
||||||
|
options.push(
|
||||||
|
<option
|
||||||
|
key='select-channel'
|
||||||
|
value=''
|
||||||
|
>
|
||||||
|
{'--- Select a channel ---'}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
|
||||||
channels.forEach((channel) => {
|
channels.forEach((channel) => {
|
||||||
if (channel.type === Constants.OPEN_CHANNEL) {
|
if (channel.type === Constants.OPEN_CHANNEL) {
|
||||||
options.push(<option value={channel.id}>{channel.name}</option>);
|
options.push(
|
||||||
|
<option
|
||||||
|
key={'outgoing-hook' + channel.id}
|
||||||
|
value={channel.id}
|
||||||
|
>
|
||||||
|
{channel.display_name}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const hooks = [];
|
const hooks = [];
|
||||||
this.state.hooks.forEach((hook) => {
|
this.state.hooks.forEach((hook) => {
|
||||||
const c = ChannelStore.get(hook.channel_id);
|
const c = ChannelStore.get(hook.channel_id);
|
||||||
|
|
||||||
|
if (!c && hook.channel_id && hook.channel_id.length !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let channelDiv;
|
let channelDiv;
|
||||||
if (c) {
|
if (c) {
|
||||||
channelDiv = (
|
channelDiv = (
|
||||||
<div className='padding-top'>
|
<div className='padding-top'>
|
||||||
<strong>{'Channel: '}</strong>{c.name}
|
<strong>{'Channel: '}</strong>{c.display_name}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -157,7 +178,10 @@ export default class ManageOutgoingHooks extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hooks.push(
|
hooks.push(
|
||||||
<div className='font--small'>
|
<div
|
||||||
|
key={hook.id}
|
||||||
|
className='font--small'
|
||||||
|
>
|
||||||
<div className='padding-top x2 divider-light'></div>
|
<div className='padding-top x2 divider-light'></div>
|
||||||
<div className='padding-top x2'>
|
<div className='padding-top x2'>
|
||||||
<strong>{'URLs: '}</strong><span className='word-break--all'>{hook.callback_urls.join(', ')}</span>
|
<strong>{'URLs: '}</strong><span className='word-break--all'>{hook.callback_urls.join(', ')}</span>
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export default class UserSettingsIntegrationsTab extends React.Component {
|
|||||||
if (global.window.mm_config.EnableIncomingWebhooks === 'true') {
|
if (global.window.mm_config.EnableIncomingWebhooks === 'true') {
|
||||||
if (this.props.activeSection === 'incoming-hooks') {
|
if (this.props.activeSection === 'incoming-hooks') {
|
||||||
inputs.push(
|
inputs.push(
|
||||||
<ManageIncomingHooks />
|
<ManageIncomingHooks key='incoming-hook-ui' />
|
||||||
);
|
);
|
||||||
|
|
||||||
incomingHooksSection = (
|
incomingHooksSection = (
|
||||||
@@ -68,7 +68,7 @@ export default class UserSettingsIntegrationsTab extends React.Component {
|
|||||||
if (global.window.mm_config.EnableOutgoingWebhooks === 'true') {
|
if (global.window.mm_config.EnableOutgoingWebhooks === 'true') {
|
||||||
if (this.props.activeSection === 'outgoing-hooks') {
|
if (this.props.activeSection === 'outgoing-hooks') {
|
||||||
inputs.push(
|
inputs.push(
|
||||||
<ManageOutgoingHooks />
|
<ManageOutgoingHooks key='outgoing-hook-ui' />
|
||||||
);
|
);
|
||||||
|
|
||||||
outgoingHooksSection = (
|
outgoingHooksSection = (
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user