Add option to trigger outgoing webhook if first word starts with trigger word (#3611)
Этот коммит содержится в:
коммит произвёл
Christopher Speller
родитель
c56b429e1d
Коммит
564dffec35
15
api/post.go
15
api/post.go
@@ -25,6 +25,11 @@ import (
|
|||||||
"github.com/mattermost/platform/utils"
|
"github.com/mattermost/platform/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
TRIGGERWORDS_FULL = 0
|
||||||
|
TRIGGERWORDS_STARTSWITH = 1
|
||||||
|
)
|
||||||
|
|
||||||
func InitPost() {
|
func InitPost() {
|
||||||
l4g.Debug(utils.T("api.post.init.debug"))
|
l4g.Debug(utils.T("api.post.init.debug"))
|
||||||
|
|
||||||
@@ -383,12 +388,14 @@ func handleWebhookEvents(c *Context, post *model.Post, team *model.Team, channel
|
|||||||
|
|
||||||
relevantHooks := []*model.OutgoingWebhook{}
|
relevantHooks := []*model.OutgoingWebhook{}
|
||||||
for _, hook := range hooks {
|
for _, hook := range hooks {
|
||||||
if hook.ChannelId == post.ChannelId {
|
if hook.ChannelId == post.ChannelId || len(hook.ChannelId) == 0 {
|
||||||
if len(hook.TriggerWords) == 0 || hook.HasTriggerWord(firstWord) {
|
if hook.ChannelId == post.ChannelId && len(hook.TriggerWords) == 0 {
|
||||||
|
relevantHooks = append(relevantHooks, hook)
|
||||||
|
} else if hook.TriggerWhen == TRIGGERWORDS_FULL && hook.HasTriggerWord(firstWord) {
|
||||||
|
relevantHooks = append(relevantHooks, hook)
|
||||||
|
} else if hook.TriggerWhen == TRIGGERWORDS_STARTSWITH && hook.TriggerWordStartsWith(firstWord) {
|
||||||
relevantHooks = append(relevantHooks, hook)
|
relevantHooks = append(relevantHooks, hook)
|
||||||
}
|
}
|
||||||
} else if len(hook.ChannelId) == 0 && hook.HasTriggerWord(firstWord) {
|
|
||||||
relevantHooks = append(relevantHooks, hook)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type OutgoingWebhook struct {
|
type OutgoingWebhook struct {
|
||||||
@@ -21,6 +22,7 @@ type OutgoingWebhook struct {
|
|||||||
ChannelId string `json:"channel_id"`
|
ChannelId string `json:"channel_id"`
|
||||||
TeamId string `json:"team_id"`
|
TeamId string `json:"team_id"`
|
||||||
TriggerWords StringArray `json:"trigger_words"`
|
TriggerWords StringArray `json:"trigger_words"`
|
||||||
|
TriggerWhen int `json:"trigger_when"`
|
||||||
CallbackURLs StringArray `json:"callback_urls"`
|
CallbackURLs StringArray `json:"callback_urls"`
|
||||||
DisplayName string `json:"display_name"`
|
DisplayName string `json:"display_name"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
@@ -171,6 +173,10 @@ func (o *OutgoingWebhook) IsValid() *AppError {
|
|||||||
return NewLocAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.content_type.app_error", nil, "")
|
return NewLocAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.content_type.app_error", nil, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if o.TriggerWhen > 1 {
|
||||||
|
return NewLocAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.content_type.app_error", nil, "")
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,3 +210,17 @@ func (o *OutgoingWebhook) HasTriggerWord(word string) bool {
|
|||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *OutgoingWebhook) TriggerWordStartsWith(word string) bool {
|
||||||
|
if len(o.TriggerWords) == 0 || len(word) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, trigger := range o.TriggerWords {
|
||||||
|
if strings.HasPrefix(word, trigger) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|||||||
@@ -163,3 +163,14 @@ func TestOutgoingWebhookPreUpdate(t *testing.T) {
|
|||||||
o := OutgoingWebhook{}
|
o := OutgoingWebhook{}
|
||||||
o.PreUpdate()
|
o.PreUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestOutgoingWebhookTriggerWordStartsWith(t *testing.T) {
|
||||||
|
o := OutgoingWebhook{Id: NewId()}
|
||||||
|
o.TriggerWords = append(o.TriggerWords, "foo")
|
||||||
|
if !o.TriggerWordStartsWith("foobar") {
|
||||||
|
t.Fatal("Should return true")
|
||||||
|
}
|
||||||
|
if o.TriggerWordStartsWith("barfoo") {
|
||||||
|
t.Fatal("Should return false")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ func NewSqlWebhookStore(sqlStore *SqlStore) WebhookStore {
|
|||||||
tableo.ColMap("DisplayName").SetMaxSize(64)
|
tableo.ColMap("DisplayName").SetMaxSize(64)
|
||||||
tableo.ColMap("Description").SetMaxSize(128)
|
tableo.ColMap("Description").SetMaxSize(128)
|
||||||
tableo.ColMap("ContentType").SetMaxSize(128)
|
tableo.ColMap("ContentType").SetMaxSize(128)
|
||||||
|
tableo.ColMap("TriggerWhen").SetMaxSize(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return s
|
return s
|
||||||
@@ -46,6 +47,7 @@ func (s SqlWebhookStore) UpgradeSchemaIfNeeded() {
|
|||||||
s.CreateColumnIfNotExists("OutgoingWebhooks", "DisplayName", "varchar(64)", "varchar(64)", "")
|
s.CreateColumnIfNotExists("OutgoingWebhooks", "DisplayName", "varchar(64)", "varchar(64)", "")
|
||||||
s.CreateColumnIfNotExists("OutgoingWebhooks", "Description", "varchar(128)", "varchar(128)", "")
|
s.CreateColumnIfNotExists("OutgoingWebhooks", "Description", "varchar(128)", "varchar(128)", "")
|
||||||
s.CreateColumnIfNotExists("OutgoingWebhooks", "ContentType", "varchar(128)", "varchar(128)", "")
|
s.CreateColumnIfNotExists("OutgoingWebhooks", "ContentType", "varchar(128)", "varchar(128)", "")
|
||||||
|
s.CreateColumnIfNotExists("OutgoingWebhooks", "TriggerWhen", "tinyint", "tinyint", "0")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s SqlWebhookStore) CreateIndexesIfNotExists() {
|
func (s SqlWebhookStore) CreateIndexesIfNotExists() {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ export default class AddOutgoingWebhook extends React.Component {
|
|||||||
this.updateContentType = this.updateContentType.bind(this);
|
this.updateContentType = this.updateContentType.bind(this);
|
||||||
this.updateChannelId = this.updateChannelId.bind(this);
|
this.updateChannelId = this.updateChannelId.bind(this);
|
||||||
this.updateTriggerWords = this.updateTriggerWords.bind(this);
|
this.updateTriggerWords = this.updateTriggerWords.bind(this);
|
||||||
|
this.updateTriggerWhen = this.updateTriggerWhen.bind(this);
|
||||||
this.updateCallbackUrls = this.updateCallbackUrls.bind(this);
|
this.updateCallbackUrls = this.updateCallbackUrls.bind(this);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
@@ -37,6 +38,7 @@ export default class AddOutgoingWebhook extends React.Component {
|
|||||||
contentType: 'application/x-www-form-urlencoded',
|
contentType: 'application/x-www-form-urlencoded',
|
||||||
channelId: '',
|
channelId: '',
|
||||||
triggerWords: '',
|
triggerWords: '',
|
||||||
|
triggerWhen: 0,
|
||||||
callbackUrls: '',
|
callbackUrls: '',
|
||||||
saving: false,
|
saving: false,
|
||||||
serverError: '',
|
serverError: '',
|
||||||
@@ -108,6 +110,7 @@ export default class AddOutgoingWebhook extends React.Component {
|
|||||||
const hook = {
|
const hook = {
|
||||||
channel_id: this.state.channelId,
|
channel_id: this.state.channelId,
|
||||||
trigger_words: triggerWords,
|
trigger_words: triggerWords,
|
||||||
|
trigger_when: parseInt(this.state.triggerWhen, 10),
|
||||||
callback_urls: callbackUrls,
|
callback_urls: callbackUrls,
|
||||||
display_name: this.state.displayName,
|
display_name: this.state.displayName,
|
||||||
content_type: this.state.contentType,
|
content_type: this.state.contentType,
|
||||||
@@ -158,6 +161,12 @@ export default class AddOutgoingWebhook extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateTriggerWhen(e) {
|
||||||
|
this.setState({
|
||||||
|
triggerWhen: e.target.value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
updateCallbackUrls(e) {
|
updateCallbackUrls(e) {
|
||||||
this.setState({
|
this.setState({
|
||||||
callbackUrls: e.target.value
|
callbackUrls: e.target.value
|
||||||
@@ -297,6 +306,41 @@ export default class AddOutgoingWebhook extends React.Component {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className='form-group'>
|
||||||
|
<label
|
||||||
|
className='control-label col-sm-4'
|
||||||
|
htmlFor='triggerWords'
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id='add_outgoing_webhook.triggerWordsTriggerWhen'
|
||||||
|
defaultMessage='Trigger When'
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<div className='col-md-5 col-sm-8'>
|
||||||
|
<select
|
||||||
|
className='form-control'
|
||||||
|
value={this.state.triggerWhen}
|
||||||
|
onChange={this.updateTriggerWhen}
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
value='0'
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id='add_outgoing_webhook.triggerWordsTriggerWhenFullWord'
|
||||||
|
defaultMessage='First word matches a trigger word exactly'
|
||||||
|
/>
|
||||||
|
</option>
|
||||||
|
<option
|
||||||
|
value='1'
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id='add_outgoing_webhook.triggerWordsTriggerWhenStartsWith'
|
||||||
|
defaultMessage='First word starts with a trigger word'
|
||||||
|
/>
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className='form-group'>
|
<div className='form-group'>
|
||||||
<label
|
<label
|
||||||
className='control-label col-sm-4'
|
className='control-label col-sm-4'
|
||||||
|
|||||||
@@ -66,6 +66,8 @@ export default class InstalledOutgoingWebhook extends React.Component {
|
|||||||
const outgoingWebhook = this.props.outgoingWebhook;
|
const outgoingWebhook = this.props.outgoingWebhook;
|
||||||
const channel = ChannelStore.get(outgoingWebhook.channel_id);
|
const channel = ChannelStore.get(outgoingWebhook.channel_id);
|
||||||
const filter = this.props.filter ? this.props.filter.toLowerCase() : '';
|
const filter = this.props.filter ? this.props.filter.toLowerCase() : '';
|
||||||
|
const triggerWordsFull = 0;
|
||||||
|
const triggerWordsStartsWith = 1;
|
||||||
|
|
||||||
if (!this.matchesFilter(outgoingWebhook, channel, filter)) {
|
if (!this.matchesFilter(outgoingWebhook, channel, filter)) {
|
||||||
return null;
|
return null;
|
||||||
@@ -127,6 +129,23 @@ export default class InstalledOutgoingWebhook extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let triggerWhen;
|
||||||
|
if (outgoingWebhook.trigger_when === triggerWordsFull) {
|
||||||
|
triggerWhen = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='add_outgoing_webhook.triggerWordsTriggerWhenFullWord'
|
||||||
|
defaultMessage='First word matches a trigger word exactly'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else if (outgoingWebhook.trigger_when === triggerWordsStartsWith) {
|
||||||
|
triggerWhen = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='add_outgoing_webhook.triggerWordsTriggerWhenStartsWith'
|
||||||
|
defaultMessage='First word starts with a trigger word'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='backstage-list__item'>
|
<div className='backstage-list__item'>
|
||||||
<div className='item-details'>
|
<div className='item-details'>
|
||||||
@@ -148,6 +167,17 @@ export default class InstalledOutgoingWebhook extends React.Component {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{triggerWords}
|
{triggerWords}
|
||||||
|
<div className='item-details__row'>
|
||||||
|
<span className='item-details__trigger-when'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='installed_integrations.triggerWhen'
|
||||||
|
defaultMessage='Trigger When: {triggerWhen}'
|
||||||
|
values={{
|
||||||
|
triggerWhen
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
<div className='item-details__row'>
|
<div className='item-details__row'>
|
||||||
<span className='item-details__token'>
|
<span className='item-details__token'>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
|
|||||||
@@ -98,6 +98,9 @@
|
|||||||
"add_outgoing_webhook.save": "Save",
|
"add_outgoing_webhook.save": "Save",
|
||||||
"add_outgoing_webhook.triggerWords": "Trigger Words (One Per Line)",
|
"add_outgoing_webhook.triggerWords": "Trigger Words (One Per Line)",
|
||||||
"add_outgoing_webhook.triggerWordsOrChannelRequired": "A valid channel or a list of trigger words is required",
|
"add_outgoing_webhook.triggerWordsOrChannelRequired": "A valid channel or a list of trigger words is required",
|
||||||
|
"add_outgoing_webhook.triggerWordsTriggerWhen": "Trigger When",
|
||||||
|
"add_outgoing_webhook.triggerWordsTriggerWhenFullWord": "First word matches a trigger word exactly",
|
||||||
|
"add_outgoing_webhook.triggerWordsTriggerWhenStartsWith": "First word starts with a trigger word",
|
||||||
"admin.audits.reload": "Reload User Activity Logs",
|
"admin.audits.reload": "Reload User Activity Logs",
|
||||||
"admin.audits.title": "User Activity Logs",
|
"admin.audits.title": "User Activity Logs",
|
||||||
"admin.authentication.email": "Email Auth",
|
"admin.authentication.email": "Email Auth",
|
||||||
@@ -1109,6 +1112,7 @@
|
|||||||
"installed_integrations.regenToken": "Regenerate Token",
|
"installed_integrations.regenToken": "Regenerate Token",
|
||||||
"installed_integrations.token": "Token: {token}",
|
"installed_integrations.token": "Token: {token}",
|
||||||
"installed_integrations.triggerWords": "Trigger Words: {triggerWords}",
|
"installed_integrations.triggerWords": "Trigger Words: {triggerWords}",
|
||||||
|
"installed_integrations.triggerWhen": "Trigger When: {triggerWhen}",
|
||||||
"installed_integrations.url": "URL: {url}",
|
"installed_integrations.url": "URL: {url}",
|
||||||
"installed_outgoing_webhooks.add": "Add Outgoing Webhook",
|
"installed_outgoing_webhooks.add": "Add Outgoing Webhook",
|
||||||
"installed_outgoing_webhooks.empty": "No outgoing webhooks found",
|
"installed_outgoing_webhooks.empty": "No outgoing webhooks found",
|
||||||
|
|||||||
@@ -247,6 +247,7 @@
|
|||||||
.item-details__content_type,
|
.item-details__content_type,
|
||||||
.item-details__token,
|
.item-details__token,
|
||||||
.item-details__trigger-words,
|
.item-details__trigger-words,
|
||||||
|
.item-details__trigger-when,
|
||||||
.item-details__url,
|
.item-details__url,
|
||||||
.item-details__creation {
|
.item-details__creation {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user