Mono repo -> Master (#22553)
Combines the following repositories into one: https://github.com/mattermost/mattermost-server https://github.com/mattermost/mattermost-webapp https://github.com/mattermost/focalboard https://github.com/mattermost/mattermost-plugin-playbooks
Этот коммит содержится в:
202
server/playbooks/client/LICENSE
Обычный файл
202
server/playbooks/client/LICENSE
Обычный файл
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
63
server/playbooks/client/action.go
Обычный файл
63
server/playbooks/client/action.go
Обычный файл
@@ -0,0 +1,63 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package client
|
||||
|
||||
type GenericChannelActionWithoutPayload struct {
|
||||
ID string `json:"id"`
|
||||
ChannelID string `json:"channel_id"`
|
||||
Enabled bool `json:"enabled"`
|
||||
DeleteAt int64 `json:"delete_at"`
|
||||
ActionType string `json:"action_type"`
|
||||
TriggerType string `json:"trigger_type"`
|
||||
}
|
||||
|
||||
type GenericChannelAction struct {
|
||||
GenericChannelActionWithoutPayload
|
||||
Payload interface{} `json:"payload"`
|
||||
}
|
||||
|
||||
type WelcomeMessagePayload struct {
|
||||
Message string `json:"message" mapstructure:"message"`
|
||||
}
|
||||
|
||||
type PromptRunPlaybookFromKeywordsPayload struct {
|
||||
Keywords []string `json:"keywords" mapstructure:"keywords"`
|
||||
PlaybookID string `json:"playbook_id" mapstructure:"playbook_id"`
|
||||
}
|
||||
|
||||
type CategorizeChannelPayload struct {
|
||||
CategoryName string `json:"category_name" mapstructure:"category_name"`
|
||||
}
|
||||
|
||||
type WelcomeMessageAction struct {
|
||||
GenericChannelActionWithoutPayload
|
||||
Payload WelcomeMessagePayload `json:"payload"`
|
||||
}
|
||||
|
||||
const (
|
||||
// Action types
|
||||
ActionTypeWelcomeMessage = "send_welcome_message"
|
||||
ActionTypePromptRunPlaybook = "prompt_run_playbook"
|
||||
ActionTypeCategorizeChannel = "categorize_channel"
|
||||
|
||||
// Trigger types
|
||||
TriggerTypeNewMemberJoins = "new_member_joins"
|
||||
TriggerTypeKeywordsPosted = "keywords"
|
||||
)
|
||||
|
||||
// ChannelActionListOptions specifies the optional parameters to the
|
||||
// ActionsService.List method.
|
||||
type ChannelActionListOptions struct {
|
||||
TriggerType string `url:"trigger_type,omitempty"`
|
||||
ActionType string `url:"action_type,omitempty"`
|
||||
}
|
||||
|
||||
// ChannelActionCreateOptions specifies the parameters for ActionsService.Create method.
|
||||
type ChannelActionCreateOptions struct {
|
||||
ChannelID string `json:"channel_id"`
|
||||
Enabled bool `json:"enabled"`
|
||||
ActionType string `json:"action_type"`
|
||||
TriggerType string `json:"trigger_type"`
|
||||
Payload interface{} `json:"payload"`
|
||||
}
|
||||
78
server/playbooks/client/actions.go
Обычный файл
78
server/playbooks/client/actions.go
Обычный файл
@@ -0,0 +1,78 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// ActionsService handles communication with the actions related
|
||||
// methods of the Playbook API.
|
||||
type ActionsService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// Create an action. Returns the id of the newly created action.
|
||||
func (s *ActionsService) Create(ctx context.Context, channelID string, opts ChannelActionCreateOptions) (string, error) {
|
||||
actionURL := fmt.Sprintf("actions/channels/%s", channelID)
|
||||
req, err := s.client.newRequest(http.MethodPost, actionURL, opts)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var result struct {
|
||||
ID string `json:"id"`
|
||||
}
|
||||
resp, err := s.client.do(ctx, req, &result)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusCreated {
|
||||
return "", fmt.Errorf("expected status code %d", http.StatusCreated)
|
||||
}
|
||||
|
||||
return result.ID, nil
|
||||
}
|
||||
|
||||
// List the actions in a channel.
|
||||
func (s *ActionsService) List(ctx context.Context, channelID string, opts ChannelActionListOptions) ([]GenericChannelAction, error) {
|
||||
actionURL, err := addOptions(fmt.Sprintf("actions/channels/%s", channelID), opts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to build options: %w", err)
|
||||
}
|
||||
|
||||
req, err := s.client.newRequest(http.MethodGet, actionURL, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to build request: %w", err)
|
||||
}
|
||||
|
||||
result := []GenericChannelAction{}
|
||||
resp, err := s.client.do(ctx, req, &result)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute request: %w", err)
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Update an existing action.
|
||||
func (s *ActionsService) Update(ctx context.Context, action GenericChannelAction) error {
|
||||
updateURL := fmt.Sprintf("actions/channels/%s/%s", action.ChannelID, action.ID)
|
||||
req, err := s.client.newRequest(http.MethodPut, updateURL, action)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = s.client.do(ctx, req, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
276
server/playbooks/client/client.go
Обычный файл
276
server/playbooks/client/client.go
Обычный файл
@@ -0,0 +1,276 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"github.com/google/go-querystring/query"
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
const (
|
||||
apiVersion = "v0"
|
||||
manifestID = "playbooks"
|
||||
userAgent = "go-client/" + apiVersion
|
||||
)
|
||||
|
||||
// Client manages communication with the Playbooks API.
|
||||
type Client struct {
|
||||
// client is the underlying HTTP client used to make API requests.
|
||||
client *http.Client
|
||||
// BaseURL is the base HTTP endpoint for the Playbooks plugin.
|
||||
BaseURL *url.URL
|
||||
// User agent used when communicating with the Playbooks API.
|
||||
UserAgent string
|
||||
|
||||
// PlaybookRuns is a collection of methods used to interact with playbook runs.
|
||||
PlaybookRuns *PlaybookRunService
|
||||
// Playbooks is a collection of methods used to interact with playbooks.
|
||||
Playbooks *PlaybooksService
|
||||
// Settings is a collection of methods used to interact with settings.
|
||||
Settings *SettingsService
|
||||
// Actions is a collection of methods used to interact with actions.
|
||||
Actions *ActionsService
|
||||
// Stats is a collection of methods used to interact with stats.
|
||||
Stats *StatsService
|
||||
// Reminders is a collection of methods used to interact with reminders.
|
||||
Reminders *RemindersService
|
||||
// Telemetry is a collection of methods used to interact with telemetry.
|
||||
Telemetry *TelemetryService
|
||||
}
|
||||
|
||||
// New creates a new instance of Client using the configuration from the given Mattermost Client.
|
||||
func New(client4 *model.Client4) (*Client, error) {
|
||||
ctx := context.Background()
|
||||
ts := oauth2.StaticTokenSource(
|
||||
&oauth2.Token{AccessToken: client4.AuthToken},
|
||||
)
|
||||
|
||||
return newClient(client4.URL, oauth2.NewClient(ctx, ts))
|
||||
}
|
||||
|
||||
// newClient creates a new instance of Client from the given URL and http.Client.
|
||||
func newClient(mattermostSiteURL string, httpClient *http.Client) (*Client, error) {
|
||||
siteURL, err := url.Parse(mattermostSiteURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c := &Client{client: httpClient, BaseURL: siteURL, UserAgent: userAgent}
|
||||
c.PlaybookRuns = &PlaybookRunService{c}
|
||||
c.Playbooks = &PlaybooksService{c}
|
||||
c.Settings = &SettingsService{c}
|
||||
c.Actions = &ActionsService{c}
|
||||
c.Stats = &StatsService{c}
|
||||
c.Reminders = &RemindersService{c}
|
||||
c.Telemetry = &TelemetryService{c}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// newRequest creates an API request, JSON-encoding any given body parameter.
|
||||
func (c *Client) newRequest(method, endpoint string, body interface{}) (*http.Request, error) {
|
||||
u, err := c.BaseURL.Parse(buildAPIURL(endpoint))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "invalid endpoint %s", endpoint)
|
||||
}
|
||||
|
||||
var buf io.ReadWriter
|
||||
if body != nil {
|
||||
buf = &bytes.Buffer{}
|
||||
enc := json.NewEncoder(buf)
|
||||
enc.SetEscapeHTML(false)
|
||||
err = enc.Encode(body)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to encode body %s", body)
|
||||
}
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, u.String(), buf)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to create http request for url %s", u)
|
||||
}
|
||||
|
||||
if buf != nil {
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
}
|
||||
if c.UserAgent != "" {
|
||||
req.Header.Set("User-Agent", c.UserAgent)
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// buildAPIURL constructs the path to the given endpoint.
|
||||
func buildAPIURL(endpoint string) string {
|
||||
return fmt.Sprintf("plugins/%s/api/%s/%s", manifestID, apiVersion, endpoint)
|
||||
}
|
||||
|
||||
// do sends an API request and returns the API response.
|
||||
//
|
||||
// The API response is JSON decoded and stored in the value pointed to by v, or returned as an
|
||||
// error if an API error has occurred. If v implements the io.Writer
|
||||
// interface, the raw response body will be written to v, without attempting to
|
||||
// first decode it.
|
||||
func (c *Client) do(ctx context.Context, req *http.Request, v interface{}) (*http.Response, error) {
|
||||
if ctx == nil {
|
||||
return nil, errors.New("context must be non-nil")
|
||||
}
|
||||
req = req.WithContext(ctx)
|
||||
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, errors.Wrapf(ctx.Err(), "client err=%s", err.Error())
|
||||
default:
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
err = checkResponse(resp)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
if v != nil {
|
||||
if w, ok := v.(io.Writer); ok {
|
||||
if _, err = io.Copy(w, resp.Body); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
|
||||
decErr := json.NewDecoder(bytes.NewReader(body)).Decode(v)
|
||||
if decErr == io.EOF {
|
||||
// TODO: Confirm if this happens only on empty bodies. If so, check that first before decoding.
|
||||
decErr = nil // ignore EOF errors caused by empty response body
|
||||
}
|
||||
if decErr != nil {
|
||||
err = decErr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
type GraphQLInput struct {
|
||||
Query string `json:"query"`
|
||||
OperationName string `json:"operationName"`
|
||||
Variables map[string]interface{} `json:"variables"`
|
||||
}
|
||||
|
||||
func (c *Client) DoGraphql(ctx context.Context, input *GraphQLInput, v interface{}) error {
|
||||
url := "query"
|
||||
req, err := c.newRequest(http.MethodPost, url, input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = c.do(ctx, req, v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkResponse checks the API response for an error.
|
||||
//
|
||||
// Any response with a status code outside 2xx is considered an error, and its body inspected for
|
||||
// an optional `Error` property in a JSON struct.
|
||||
func checkResponse(r *http.Response) error {
|
||||
if c := r.StatusCode; http.StatusOK <= c && c <= 299 {
|
||||
return nil
|
||||
}
|
||||
|
||||
errorResponse := &ErrorResponse{
|
||||
StatusCode: r.StatusCode,
|
||||
Method: r.Request.Method,
|
||||
URL: r.Request.URL.String(),
|
||||
}
|
||||
data, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
errorResponse.Err = fmt.Errorf("failed to read response body: %w", err)
|
||||
}
|
||||
r.Body = ioutil.NopCloser(bytes.NewBuffer(data))
|
||||
|
||||
if data != nil {
|
||||
_ = json.Unmarshal(data, errorResponse)
|
||||
}
|
||||
|
||||
return errorResponse
|
||||
}
|
||||
|
||||
// addOption adds the given parameter as an URL query parameters to s.
|
||||
func addOption(s string, name, value string) (string, error) {
|
||||
u, err := url.Parse(s)
|
||||
if err != nil {
|
||||
return s, errors.Wrapf(err, "failed to parse %s", s)
|
||||
}
|
||||
|
||||
qa := u.Query()
|
||||
qa.Add(name, value)
|
||||
u.RawQuery = qa.Encode()
|
||||
|
||||
return u.String(), nil
|
||||
}
|
||||
|
||||
// addOptions adds the parameters in opts as URL query parameters to s. opts
|
||||
// must be a struct whose fields may contain "url" tags.
|
||||
func addOptions(s string, opts interface{}) (string, error) {
|
||||
v := reflect.ValueOf(opts)
|
||||
if v.Kind() == reflect.Ptr && v.IsNil() {
|
||||
return s, nil
|
||||
}
|
||||
|
||||
u, err := url.Parse(s)
|
||||
if err != nil {
|
||||
return s, errors.Wrapf(err, "failed to parse %s", s)
|
||||
}
|
||||
|
||||
qs, err := query.Values(opts)
|
||||
if err != nil {
|
||||
return s, errors.Wrapf(err, "failed to opts %+v", opts)
|
||||
}
|
||||
|
||||
// Append to the existing query parameters.
|
||||
qa := u.Query()
|
||||
for key, values := range qs {
|
||||
for _, value := range values {
|
||||
qa.Add(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
u.RawQuery = qa.Encode()
|
||||
return u.String(), nil
|
||||
}
|
||||
|
||||
// addPaginationOptions adds the given pagination parameters as URL query parameters to s.
|
||||
func addPaginationOptions(s string, page, perPage int) (string, error) {
|
||||
u, err := url.Parse(s)
|
||||
if err != nil {
|
||||
return s, errors.Wrapf(err, "failed to parse %s", s)
|
||||
}
|
||||
|
||||
qa := u.Query()
|
||||
qa.Add("page", strconv.Itoa(page))
|
||||
qa.Add("per_page", strconv.Itoa(perPage))
|
||||
u.RawQuery = qa.Encode()
|
||||
|
||||
return u.String(), nil
|
||||
}
|
||||
5
server/playbooks/client/doc.go
Обычный файл
5
server/playbooks/client/doc.go
Обычный файл
@@ -0,0 +1,5 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// Package client provides an HTTP client for using the Playbooks API.
|
||||
package client
|
||||
36
server/playbooks/client/doc_test.go
Обычный файл
36
server/playbooks/client/doc_test.go
Обычный файл
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package client_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
"github.com/mattermost/mattermost-server/v6/server/playbooks/client"
|
||||
)
|
||||
|
||||
func Example() {
|
||||
ctx := context.Background()
|
||||
|
||||
client4 := model.NewAPIv4Client("http://localhost:8065")
|
||||
_, _, err := client4.Login("test@example.com", "testtest")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
c, err := client.New(client4)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
playbookRunID := "h4n3h7s1qjf5pkis4dn6cuxgwa"
|
||||
playbookRun, err := c.PlaybookRuns.Get(ctx, playbookRunID)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Printf("Playbook Run Name: %s\n", playbookRun.Name)
|
||||
}
|
||||
52
server/playbooks/client/error_response.go
Обычный файл
52
server/playbooks/client/error_response.go
Обычный файл
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// ErrorResponse is an error from an API request.
|
||||
type ErrorResponse struct {
|
||||
// Method is the HTTP verb used in the API request.
|
||||
Method string
|
||||
// URL is the HTTP endpoint used in the API request.
|
||||
URL string
|
||||
// StatusCode is the HTTP status code returned by the API.
|
||||
StatusCode int
|
||||
|
||||
// Err is the error parsed from the API response.
|
||||
Err error `json:"error"`
|
||||
}
|
||||
|
||||
func (e *ErrorResponse) UnmarshalJSON(data []byte) error {
|
||||
type Alias ErrorResponse
|
||||
temp := &struct {
|
||||
Err string `json:"error"`
|
||||
*Alias
|
||||
}{
|
||||
Alias: (*Alias)(e),
|
||||
}
|
||||
|
||||
// Try to extract a structured error from the body, otherwise fall back to using
|
||||
// the whole body as the error message.
|
||||
if err := json.Unmarshal(data, &temp); err != nil || temp.Err == "" {
|
||||
e.Err = errors.New(string(data))
|
||||
} else {
|
||||
e.Err = errors.New(temp.Err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unwrap exposes the underlying error of an ErrorResponse.
|
||||
func (e *ErrorResponse) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
// Error describes the error from the API request.
|
||||
func (e *ErrorResponse) Error() string {
|
||||
return fmt.Sprintf("%s %s [%d]: %v", e.Method, e.URL, e.StatusCode, e.Err)
|
||||
}
|
||||
192
server/playbooks/client/playbook.go
Обычный файл
192
server/playbooks/client/playbook.go
Обычный файл
@@ -0,0 +1,192 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/guregu/null.v4"
|
||||
)
|
||||
|
||||
// Playbook represents the planning before a playbook run is initiated.
|
||||
type Playbook struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Public bool `json:"public"`
|
||||
TeamID string `json:"team_id"`
|
||||
CreatePublicPlaybookRun bool `json:"create_public_playbook_run"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
DeleteAt int64 `json:"delete_at"`
|
||||
NumStages int64 `json:"num_stages"`
|
||||
NumSteps int64 `json:"num_steps"`
|
||||
Checklists []Checklist `json:"checklists"`
|
||||
Members []PlaybookMember `json:"members"`
|
||||
ReminderMessageTemplate string `json:"reminder_message_template"`
|
||||
ReminderTimerDefaultSeconds int64 `json:"reminder_timer_default_seconds"`
|
||||
InvitedUserIDs []string `json:"invited_user_ids"`
|
||||
InvitedGroupIDs []string `json:"invited_group_ids"`
|
||||
InviteUsersEnabled bool `json:"invite_users_enabled"`
|
||||
DefaultOwnerID string `json:"default_owner_id"`
|
||||
DefaultOwnerEnabled bool `json:"default_owner_enabled"`
|
||||
BroadcastChannelIDs []string `json:"broadcast_channel_ids"`
|
||||
BroadcastEnabled bool `json:"broadcast_enabled"`
|
||||
WebhookOnCreationURLs []string `json:"webhook_on_creation_urls"`
|
||||
WebhookOnCreationEnabled bool `json:"webhook_on_creation_enabled"`
|
||||
Metrics []PlaybookMetricConfig `json:"metrics"`
|
||||
CreateChannelMemberOnNewParticipant bool `json:"create_channel_member_on_new_participant"`
|
||||
RemoveChannelMemberOnRemovedParticipant bool `json:"remove_channel_member_on_removed_participant"`
|
||||
ChannelID string `json:"channel_id" export:"channel_id"`
|
||||
ChannelMode ChannelPlaybookMode `json:"channel_mode" export:"channel_mode"`
|
||||
}
|
||||
|
||||
type PlaybookMember struct {
|
||||
UserID string `json:"user_id"`
|
||||
Roles []string `json:"roles"`
|
||||
SchemeRoles []string `json:"scheme_roles"`
|
||||
}
|
||||
|
||||
const (
|
||||
MetricTypeDuration = "metric_duration"
|
||||
MetricTypeCurrency = "metric_currency"
|
||||
MetricTypeInteger = "metric_integer"
|
||||
)
|
||||
|
||||
// Checklist represents a checklist in a playbook
|
||||
type Checklist struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Items []ChecklistItem `json:"items"`
|
||||
}
|
||||
|
||||
// ChecklistItem represents an item in a checklist
|
||||
type ChecklistItem struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
State string `json:"state"`
|
||||
StateModified int64 `json:"state_modified"`
|
||||
AssigneeID string `json:"assignee_id"`
|
||||
AssigneeModified int64 `json:"assignee_modified"`
|
||||
Command string `json:"command"`
|
||||
CommandLastRun int64 `json:"command_last_run"`
|
||||
Description string `json:"description"`
|
||||
LastSkipped int64 `json:"delete_at"`
|
||||
DueDate int64 `json:"due_date"`
|
||||
TaskActions []TaskAction `json:"task_actions"`
|
||||
}
|
||||
|
||||
// TaskAction represents a task action in an item
|
||||
type TaskAction struct {
|
||||
Trigger TriggerAction `json:"trigger"`
|
||||
Actions []TriggerAction `json:"actions"`
|
||||
}
|
||||
|
||||
// TriggerAction represents a trigger or action in a Task Action
|
||||
type TriggerAction struct {
|
||||
Type string `json:"type"`
|
||||
Payload string `json:"payload"`
|
||||
}
|
||||
|
||||
// PlaybookCreateOptions specifies the parameters for PlaybooksService.Create method.
|
||||
type PlaybookCreateOptions struct {
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
TeamID string `json:"team_id"`
|
||||
Public bool `json:"public"`
|
||||
CreatePublicPlaybookRun bool `json:"create_public_playbook_run"`
|
||||
Checklists []Checklist `json:"checklists"`
|
||||
Members []PlaybookMember `json:"members"`
|
||||
BroadcastChannelID string `json:"broadcast_channel_id"`
|
||||
ReminderMessageTemplate string `json:"reminder_message_template"`
|
||||
ReminderTimerDefaultSeconds int64 `json:"reminder_timer_default_seconds"`
|
||||
InvitedUserIDs []string `json:"invited_user_ids"`
|
||||
InvitedGroupIDs []string `json:"invited_group_ids"`
|
||||
InviteUsersEnabled bool `json:"invite_users_enabled"`
|
||||
DefaultOwnerID string `json:"default_owner_id"`
|
||||
DefaultOwnerEnabled bool `json:"default_owner_enabled"`
|
||||
BroadcastChannelIDs []string `json:"broadcast_channel_ids"`
|
||||
BroadcastEnabled bool `json:"broadcast_enabled"`
|
||||
Metrics []PlaybookMetricConfig `json:"metrics"`
|
||||
CreateChannelMemberOnNewParticipant bool `json:"create_channel_member_on_new_participant"`
|
||||
RemoveChannelMemberOnRemovedParticipant bool `json:"remove_channel_member_on_removed_participant"`
|
||||
ChannelID string `json:"channel_id" export:"channel_id"`
|
||||
ChannelMode ChannelPlaybookMode `json:"channel_mode" export:"channel_mode"`
|
||||
}
|
||||
|
||||
type PlaybookMetricConfig struct {
|
||||
ID string `json:"id"`
|
||||
PlaybookID string `json:"playbook_id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Target null.Int `json:"target"`
|
||||
}
|
||||
|
||||
// PlaybookListOptions specifies the optional parameters to the
|
||||
// PlaybooksService.List method.
|
||||
type PlaybookListOptions struct {
|
||||
Sort Sort `url:"sort,omitempty"`
|
||||
Direction SortDirection `url:"direction,omitempty"`
|
||||
SearchTeam string `url:"search_term,omitempty"`
|
||||
WithArchived bool `url:"with_archived,omitempty"`
|
||||
}
|
||||
|
||||
type GetPlaybooksResults struct {
|
||||
TotalCount int `json:"total_count"`
|
||||
PageCount int `json:"page_count"`
|
||||
HasMore bool `json:"has_more"`
|
||||
Items []Playbook `json:"items"`
|
||||
}
|
||||
|
||||
type PlaybookStats struct {
|
||||
RunsInProgress int `json:"runs_in_progress"`
|
||||
ParticipantsActive int `json:"participants_active"`
|
||||
RunsFinishedPrev30Days int `json:"runs_finished_prev_30_days"`
|
||||
RunsFinishedPercentageChange int `json:"runs_finished_percentage_change"`
|
||||
RunsStartedPerWeek []int `json:"runs_started_per_week"`
|
||||
RunsStartedPerWeekTimes [][]int64 `json:"runs_started_per_week_times"`
|
||||
ActiveRunsPerDay []int `json:"active_runs_per_day"`
|
||||
ActiveRunsPerDayTimes [][]int64 `json:"active_runs_per_day_times"`
|
||||
ActiveParticipantsPerDay []int `json:"active_participants_per_day"`
|
||||
ActiveParticipantsPerDayTimes [][]int64 `json:"active_participants_per_day_times"`
|
||||
MetricOverallAverage []null.Int `json:"metric_overall_average"`
|
||||
MetricRollingAverage []null.Int `json:"metric_rolling_average"`
|
||||
MetricRollingAverageChange []null.Int `json:"metric_rolling_average_change"`
|
||||
MetricValueRange [][]int64 `json:"metric_value_range"`
|
||||
MetricRollingValues [][]int64 `json:"metric_rolling_values"`
|
||||
LastXRunNames []string `json:"last_x_run_names"`
|
||||
}
|
||||
|
||||
type ChannelPlaybookMode int
|
||||
|
||||
const (
|
||||
PlaybookRunCreateNewChannel ChannelPlaybookMode = iota
|
||||
PlaybookRunLinkExistingChannel
|
||||
)
|
||||
|
||||
var channelPlaybookTypes = [...]string{
|
||||
PlaybookRunCreateNewChannel: "create_new_channel",
|
||||
PlaybookRunLinkExistingChannel: "link_existing_channel",
|
||||
}
|
||||
|
||||
// String creates the string version of the TelemetryTrack
|
||||
func (cpm ChannelPlaybookMode) String() string {
|
||||
return channelPlaybookTypes[cpm]
|
||||
}
|
||||
|
||||
// MarshalText converts a ChannelPlaybookMode to a string for serializers (including JSON)
|
||||
func (cpm ChannelPlaybookMode) MarshalText() ([]byte, error) {
|
||||
return []byte(channelPlaybookTypes[cpm]), nil
|
||||
}
|
||||
|
||||
// UnmarshalText parses a ChannelPlaybookMode from text. For deserializers (including JSON)
|
||||
func (cpm *ChannelPlaybookMode) UnmarshalText(text []byte) error {
|
||||
for i, st := range channelPlaybookTypes {
|
||||
if st == string(text) {
|
||||
*cpm = ChannelPlaybookMode(i)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("unknown ChannelPlaybookMode: %s", string(text))
|
||||
}
|
||||
292
server/playbooks/client/playbook_run.go
Обычный файл
292
server/playbooks/client/playbook_run.go
Обычный файл
@@ -0,0 +1,292 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gopkg.in/guregu/null.v4"
|
||||
)
|
||||
|
||||
// Me is a constant that refers to the current user, and can be used in various APIs in place of
|
||||
// explicitly specifying the current user's id.
|
||||
const Me = "me"
|
||||
|
||||
// PlaybookRun represents a playbook run.
|
||||
type PlaybookRun struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Summary string `json:"summary"`
|
||||
SummaryModifiedAt int64 `json:"summary_modified_at"`
|
||||
OwnerUserID string `json:"owner_user_id"`
|
||||
ReporterUserID string `json:"reporter_user_id"`
|
||||
TeamID string `json:"team_id"`
|
||||
ChannelID string `json:"channel_id"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
EndAt int64 `json:"end_at"`
|
||||
DeleteAt int64 `json:"delete_at"`
|
||||
ActiveStage int `json:"active_stage"`
|
||||
ActiveStageTitle string `json:"active_stage_title"`
|
||||
PostID string `json:"post_id"`
|
||||
PlaybookID string `json:"playbook_id"`
|
||||
Checklists []Checklist `json:"checklists"`
|
||||
StatusPosts []StatusPost `json:"status_posts"`
|
||||
CurrentStatus string `json:"current_status"`
|
||||
LastStatusUpdateAt int64 `json:"last_status_update_at"`
|
||||
ReminderPostID string `json:"reminder_post_id"`
|
||||
PreviousReminder time.Duration `json:"previous_reminder"`
|
||||
ReminderTimerDefaultSeconds int64 `json:"reminder_timer_default_seconds"`
|
||||
StatusUpdateEnabled bool `json:"status_update_enabled"`
|
||||
BroadcastChannelIDs []string `json:"broadcast_channel_ids"`
|
||||
WebhookOnStatusUpdateURLs []string `json:"webhook_on_status_update_urls"`
|
||||
StatusUpdateBroadcastChannelsEnabled bool `json:"status_update_broadcast_channels_enabled"`
|
||||
StatusUpdateBroadcastWebhooksEnabled bool `json:"status_update_broadcast_webhooks_enabled"`
|
||||
ReminderMessageTemplate string `json:"reminder_message_template"`
|
||||
InvitedUserIDs []string `json:"invited_user_ids"`
|
||||
InvitedGroupIDs []string `json:"invited_group_ids"`
|
||||
TimelineEvents []TimelineEvent `json:"timeline_events"`
|
||||
DefaultOwnerID string `json:"default_owner_id"`
|
||||
WebhookOnCreationURLs []string `json:"webhook_on_creation_urls"`
|
||||
Retrospective string `json:"retrospective"`
|
||||
RetrospectivePublishedAt int64 `json:"retrospective_published_at"`
|
||||
RetrospectiveWasCanceled bool `json:"retrospective_was_canceled"`
|
||||
RetrospectiveReminderIntervalSeconds int64 `json:"retrospective_reminder_interval_seconds"`
|
||||
RetrospectiveEnabled bool `json:"retrospective_enabled"`
|
||||
MessageOnJoin string `json:"message_on_join"`
|
||||
ParticipantIDs []string `json:"participant_ids"`
|
||||
CategoryName string `json:"category_name"`
|
||||
MetricsData []RunMetricData `json:"metrics_data"`
|
||||
CreateChannelMemberOnNewParticipant bool `json:"create_channel_member_on_new_participant"`
|
||||
RemoveChannelMemberOnRemovedParticipant bool `json:"remove_channel_member_on_removed_participant"`
|
||||
}
|
||||
|
||||
// StatusPost is information added to the playbook run when selecting from the db and sent to the
|
||||
// client; it is not saved to the db.
|
||||
type StatusPost struct {
|
||||
ID string `json:"id"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
DeleteAt int64 `json:"delete_at"`
|
||||
}
|
||||
|
||||
// StatusPostComplete is the complete status update (post)
|
||||
// it's similar to StatusPost but with extended info.
|
||||
type StatusPostComplete struct {
|
||||
Id string `json:"id"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
UpdateAt int64 `json:"update_at"`
|
||||
DeleteAt int64 `json:"delete_at"`
|
||||
Message string `json:"message"`
|
||||
AuthorUserName string `json:"author_user_name"`
|
||||
}
|
||||
|
||||
// Metadata tracks ancillary metadata about a playbook run.
|
||||
type Metadata struct {
|
||||
ChannelName string `json:"channel_name"`
|
||||
ChannelDisplayName string `json:"channel_display_name"`
|
||||
TeamName string `json:"team_name"`
|
||||
NumParticipants int64 `json:"num_participants"`
|
||||
TotalPosts int64 `json:"total_posts"`
|
||||
Followers []string `json:"followers"`
|
||||
}
|
||||
|
||||
// TimelineEventType describes a type of timeline event.
|
||||
type TimelineEventType string
|
||||
|
||||
const (
|
||||
PlaybookRunCreated TimelineEventType = "incident_created"
|
||||
TaskStateModified TimelineEventType = "task_state_modified"
|
||||
StatusUpdated TimelineEventType = "status_updated"
|
||||
StatusUpdateRequested TimelineEventType = "status_update_requested"
|
||||
OwnerChanged TimelineEventType = "owner_changed"
|
||||
AssigneeChanged TimelineEventType = "assignee_changed"
|
||||
RanSlashCommand TimelineEventType = "ran_slash_command"
|
||||
EventFromPost TimelineEventType = "event_from_post"
|
||||
UserJoinedLeft TimelineEventType = "user_joined_left"
|
||||
PublishedRetrospective TimelineEventType = "published_retrospective"
|
||||
CanceledRetrospective TimelineEventType = "canceled_retrospective"
|
||||
RunFinished TimelineEventType = "run_finished"
|
||||
RunRestored TimelineEventType = "run_restored"
|
||||
StatusUpdatesEnabled TimelineEventType = "status_updates_enabled"
|
||||
StatusUpdatesDisabled TimelineEventType = "status_updates_disabled"
|
||||
)
|
||||
|
||||
// TimelineEvent represents an event recorded to a playbook run's timeline.
|
||||
type TimelineEvent struct {
|
||||
ID string `json:"id"`
|
||||
PlaybookRunID string `json:"playbook_run"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
DeleteAt int64 `json:"delete_at"`
|
||||
EventAt int64 `json:"event_at"`
|
||||
EventType TimelineEventType `json:"event_type"`
|
||||
Summary string `json:"summary"`
|
||||
Details string `json:"details"`
|
||||
PostID string `json:"post_id"`
|
||||
SubjectUserID string `json:"subject_user_id"`
|
||||
CreatorUserID string `json:"creator_user_id"`
|
||||
}
|
||||
|
||||
// PlaybookRunCreateOptions specifies the parameters for PlaybookRunService.Create method.
|
||||
type PlaybookRunCreateOptions struct {
|
||||
Name string `json:"name"`
|
||||
OwnerUserID string `json:"owner_user_id"`
|
||||
TeamID string `json:"team_id"`
|
||||
ChannelID string `json:"channel_id"`
|
||||
Description string `json:"description"`
|
||||
PostID string `json:"post_id"`
|
||||
PlaybookID string `json:"playbook_id"`
|
||||
CreatePublicRun *bool `json:"create_public_run"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// RunAction represents the run action settings. Frontend passes this struct to update settings.
|
||||
type RunAction struct {
|
||||
BroadcastChannelIDs []string `json:"broadcast_channel_ids"`
|
||||
WebhookOnStatusUpdateURLs []string `json:"webhook_on_status_update_urls"`
|
||||
|
||||
StatusUpdateBroadcastChannelsEnabled bool `json:"status_update_broadcast_channels_enabled"`
|
||||
StatusUpdateBroadcastWebhooksEnabled bool `json:"status_update_broadcast_webhooks_enabled"`
|
||||
}
|
||||
|
||||
// RetrospectiveUpdate represents the run retrospective info
|
||||
type RetrospectiveUpdate struct {
|
||||
Text string `json:"retrospective"`
|
||||
Metrics []RunMetricData `json:"metrics"`
|
||||
}
|
||||
|
||||
// Sort enumerates the available fields we can sort on.
|
||||
type Sort string
|
||||
|
||||
const (
|
||||
// SortByCreateAt sorts by the "create_at" field. It is the default.
|
||||
SortByCreateAt Sort = "create_at"
|
||||
|
||||
// SortByID sorts by the "id" field.
|
||||
SortByID Sort = "id"
|
||||
|
||||
// SortByName sorts by the "name" field.
|
||||
SortByName Sort = "name"
|
||||
|
||||
// SortByOwnerUserID sorts by the "owner_user_id" field.
|
||||
SortByOwnerUserID Sort = "owner_user_id"
|
||||
|
||||
// SortByTeamID sorts by the "team_id" field.
|
||||
SortByTeamID Sort = "team_id"
|
||||
|
||||
// SortByEndAt sorts by the "end_at" field.
|
||||
SortByEndAt Sort = "end_at"
|
||||
|
||||
// SortBySteps sorts playbooks by the number of steps in the playbook.
|
||||
SortBySteps Sort = "steps"
|
||||
|
||||
// SortByStages sorts playbooks by the number of stages in the playbook.
|
||||
SortByStages Sort = "stages"
|
||||
|
||||
// SortByTitle sorts by the "title" field.
|
||||
SortByTitle Sort = "title"
|
||||
|
||||
// SortByRuns sorts by the number of times a playbook has been run.
|
||||
SortByRuns Sort = "runs"
|
||||
)
|
||||
|
||||
// SortDirection determines whether results are sorted ascending or descending.
|
||||
type SortDirection string
|
||||
|
||||
const (
|
||||
// Desc sorts the results in descending order.
|
||||
SortDesc SortDirection = "desc"
|
||||
|
||||
// Asc sorts the results in ascending order.
|
||||
SortAsc SortDirection = "asc"
|
||||
)
|
||||
|
||||
// PlaybookRunListOptions specifies the optional parameters to the
|
||||
// PlaybookRunService.List method.
|
||||
type PlaybookRunListOptions struct {
|
||||
// TeamID filters playbook runs to those in the given team.
|
||||
TeamID string `url:"team_id,omitempty"`
|
||||
|
||||
Sort Sort `url:"sort,omitempty"`
|
||||
Direction SortDirection `url:"direction,omitempty"`
|
||||
|
||||
// Statuses filters by InProgress or Ended; defaults to All when no status specified.
|
||||
Statuses []Status `url:"statuses,omitempty"`
|
||||
|
||||
// OwnerID filters by owner's Mattermost user ID. Defaults to blank (no filter). Specify "me" for current user.
|
||||
OwnerID string `url:"owner_user_id,omitempty"`
|
||||
|
||||
// ParticipantID filters playbook runs that have this user as a participant. Defaults to blank (no filter). Specify "me" for current user.
|
||||
ParticipantID string `url:"participant_id,omitempty"`
|
||||
|
||||
// ParticipantOrFollowerID filters playbook runs that have this user as member or as follower. Defaults to blank (no filter). Specify "me" for current user.
|
||||
ParticipantOrFollowerID string `url:"participant_or_follower,omitempty"`
|
||||
|
||||
// SearchTerm returns results of the search term and respecting the other header filter options.
|
||||
// The search term acts as a filter and respects the Sort and Direction fields (i.e., results are
|
||||
// not returned in relevance order).
|
||||
SearchTerm string `url:"search_term,omitempty"`
|
||||
|
||||
// PlaybookID filters playbook runs that are derived from this playbook id.
|
||||
// Defaults to blank (no filter).
|
||||
PlaybookID string `url:"playbook_id,omitempty"`
|
||||
|
||||
// ActiveGTE filters playbook runs that were active after (or equal) to the unix time given (in millis).
|
||||
// A value of 0 means the filter is ignored (which is the default).
|
||||
ActiveGTE int64 `url:"active_gte,omitempty"`
|
||||
|
||||
// ActiveLT filters playbook runs that were active before the unix time given (in millis).
|
||||
// A value of 0 means the filter is ignored (which is the default).
|
||||
ActiveLT int64 `url:"active_lt,omitempty"`
|
||||
|
||||
// StartedGTE filters playbook runs that were started after (or equal) to the unix time given (in millis).
|
||||
// A value of 0 means the filter is ignored (which is the default).
|
||||
StartedGTE int64 `url:"started_gte,omitempty"`
|
||||
|
||||
// StartedLT filters playbook runs that were started before the unix time given (in millis).
|
||||
// A value of 0 means the filter is ignored (which is the default).
|
||||
StartedLT int64 `url:"started_lt,omitempty"`
|
||||
}
|
||||
|
||||
// PlaybookRunList contains the paginated result.
|
||||
type PlaybookRunList struct {
|
||||
TotalCount int `json:"total_count"`
|
||||
PageCount int `json:"page_count"`
|
||||
HasMore bool `json:"has_more"`
|
||||
Items []*PlaybookRun
|
||||
}
|
||||
|
||||
// Status is the type used to specify the activity status of the playbook run.
|
||||
type Status string
|
||||
|
||||
const (
|
||||
StatusInProgress Status = "InProgress"
|
||||
StatusFinished Status = "Finished"
|
||||
)
|
||||
|
||||
type GetPlaybookRunsResults struct {
|
||||
TotalCount int `json:"total_count"`
|
||||
PageCount int `json:"page_count"`
|
||||
HasMore bool `json:"has_more"`
|
||||
Items []PlaybookRun `json:"items"`
|
||||
}
|
||||
|
||||
// StatusUpdateOptions are the fields required to update a playbook run's status
|
||||
type StatusUpdateOptions struct {
|
||||
Message string `json:"message"`
|
||||
Reminder time.Duration `json:"reminder"`
|
||||
FinishRun bool `json:"finish_run"`
|
||||
}
|
||||
|
||||
type RunMetricData struct {
|
||||
MetricConfigID string `json:"metric_config_id"`
|
||||
Value null.Int `json:"value"`
|
||||
}
|
||||
|
||||
// OwnerInfo holds the summary information of a owner.
|
||||
type OwnerInfo struct {
|
||||
UserID string `json:"user_id"`
|
||||
Username string `json:"username"`
|
||||
FirstName string `json:"first_name"`
|
||||
LastName string `json:"last_name"`
|
||||
Nickname string `json:"nickname"`
|
||||
}
|
||||
375
server/playbooks/client/playbook_runs.go
Обычный файл
375
server/playbooks/client/playbook_runs.go
Обычный файл
@@ -0,0 +1,375 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// PlaybookRunService handles communication with the playbook run related
|
||||
// methods of the Playbooks API.
|
||||
type PlaybookRunService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// Get a playbook run.
|
||||
func (s *PlaybookRunService) Get(ctx context.Context, playbookRunID string) (*PlaybookRun, error) {
|
||||
playbookRunURL := fmt.Sprintf("runs/%s", playbookRunID)
|
||||
req, err := s.client.newRequest(http.MethodGet, playbookRunURL, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
playbookRun := new(PlaybookRun)
|
||||
resp, err := s.client.do(ctx, req, playbookRun)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
return playbookRun, nil
|
||||
}
|
||||
|
||||
// GetByChannelID gets a playbook run by ChannelID.
|
||||
func (s *PlaybookRunService) GetByChannelID(ctx context.Context, channelID string) (*PlaybookRun, error) {
|
||||
channelURL := fmt.Sprintf("runs/channel/%s", channelID)
|
||||
req, err := s.client.newRequest(http.MethodGet, channelURL, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
playbookRun := new(PlaybookRun)
|
||||
resp, err := s.client.do(ctx, req, playbookRun)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
return playbookRun, nil
|
||||
}
|
||||
|
||||
// Get a playbook run's metadata.
|
||||
func (s *PlaybookRunService) GetMetadata(ctx context.Context, playbookRunID string) (*Metadata, error) {
|
||||
playbookRunURL := fmt.Sprintf("runs/%s/metadata", playbookRunID)
|
||||
req, err := s.client.newRequest(http.MethodGet, playbookRunURL, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
playbookRun := new(Metadata)
|
||||
resp, err := s.client.do(ctx, req, playbookRun)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
return playbookRun, nil
|
||||
}
|
||||
|
||||
// Get all playbook status updates.
|
||||
func (s *PlaybookRunService) GetStatusUpdates(ctx context.Context, playbookRunID string) ([]StatusPostComplete, error) {
|
||||
playbookRunURL := fmt.Sprintf("runs/%s/status-updates", playbookRunID)
|
||||
req, err := s.client.newRequest(http.MethodGet, playbookRunURL, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var statusUpdates []StatusPostComplete
|
||||
resp, err := s.client.do(ctx, req, &statusUpdates)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
return statusUpdates, nil
|
||||
}
|
||||
|
||||
// List the playbook runs.
|
||||
func (s *PlaybookRunService) List(ctx context.Context, page, perPage int, opts PlaybookRunListOptions) (*GetPlaybookRunsResults, error) {
|
||||
playbookRunURL := "runs"
|
||||
playbookRunURL, err := addOptions(playbookRunURL, opts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to build options: %w", err)
|
||||
}
|
||||
playbookRunURL, err = addPaginationOptions(playbookRunURL, page, perPage)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to build pagination options: %w", err)
|
||||
}
|
||||
|
||||
req, err := s.client.newRequest(http.MethodGet, playbookRunURL, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to build request: %w", err)
|
||||
}
|
||||
|
||||
result := &GetPlaybookRunsResults{}
|
||||
resp, err := s.client.do(ctx, req, result)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute request: %w", err)
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Create a playbook run.
|
||||
func (s *PlaybookRunService) Create(ctx context.Context, opts PlaybookRunCreateOptions) (*PlaybookRun, error) {
|
||||
playbookRunURL := "runs"
|
||||
req, err := s.client.newRequest(http.MethodPost, playbookRunURL, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
playbookRun := new(PlaybookRun)
|
||||
resp, err := s.client.do(ctx, req, playbookRun)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusCreated {
|
||||
return nil, fmt.Errorf("expected status code %d", http.StatusCreated)
|
||||
}
|
||||
|
||||
return playbookRun, nil
|
||||
}
|
||||
|
||||
func (s *PlaybookRunService) UpdateStatus(ctx context.Context, playbookRunID string, message string, reminderInSeconds int64) error {
|
||||
updateURL := fmt.Sprintf("runs/%s/status", playbookRunID)
|
||||
opts := StatusUpdateOptions{
|
||||
Message: message,
|
||||
Reminder: time.Duration(reminderInSeconds),
|
||||
}
|
||||
req, err := s.client.newRequest(http.MethodPost, updateURL, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := s.client.do(ctx, req, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("expected status code %d", http.StatusOK)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *PlaybookRunService) RequestUpdate(ctx context.Context, playbookRunID, userID string) error {
|
||||
requestURL := fmt.Sprintf("runs/%s/request-update", playbookRunID)
|
||||
req, err := s.client.newRequest(http.MethodPost, requestURL, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := s.client.do(ctx, req, nil)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("expected status code %d", http.StatusOK)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *PlaybookRunService) Finish(ctx context.Context, playbookRunID string) error {
|
||||
finishURL := fmt.Sprintf("runs/%s/finish", playbookRunID)
|
||||
req, err := s.client.newRequest(http.MethodPut, finishURL, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = s.client.do(ctx, req, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *PlaybookRunService) CreateChecklist(ctx context.Context, playbookRunID string, checklist Checklist) error {
|
||||
createURL := fmt.Sprintf("runs/%s/checklists", playbookRunID)
|
||||
req, err := s.client.newRequest(http.MethodPost, createURL, checklist)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = s.client.do(ctx, req, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *PlaybookRunService) RemoveChecklist(ctx context.Context, playbookRunID string, checklistNumber int) error {
|
||||
createURL := fmt.Sprintf("runs/%s/checklists/%d", playbookRunID, checklistNumber)
|
||||
req, err := s.client.newRequest(http.MethodDelete, createURL, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = s.client.do(ctx, req, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *PlaybookRunService) RenameChecklist(ctx context.Context, playbookRunID string, checklistNumber int, newTitle string) error {
|
||||
createURL := fmt.Sprintf("runs/%s/checklists/%d/rename", playbookRunID, checklistNumber)
|
||||
req, err := s.client.newRequest(http.MethodPut, createURL, struct{ Title string }{newTitle})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = s.client.do(ctx, req, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *PlaybookRunService) AddChecklistItem(ctx context.Context, playbookRunID string, checklistNumber int, checklistItem ChecklistItem) error {
|
||||
addURL := fmt.Sprintf("runs/%s/checklists/%d/add", playbookRunID, checklistNumber)
|
||||
req, err := s.client.newRequest(http.MethodPost, addURL, checklistItem)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = s.client.do(ctx, req, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *PlaybookRunService) MoveChecklist(ctx context.Context, playbookRunID string, sourceChecklistIdx, destChecklistIdx int) error {
|
||||
createURL := fmt.Sprintf("runs/%s/checklists/move", playbookRunID)
|
||||
body := struct {
|
||||
SourceChecklistIdx int `json:"source_checklist_idx"`
|
||||
DestChecklistIdx int `json:"dest_checklist_idx"`
|
||||
}{sourceChecklistIdx, destChecklistIdx}
|
||||
|
||||
req, err := s.client.newRequest(http.MethodPost, createURL, body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = s.client.do(ctx, req, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *PlaybookRunService) MoveChecklistItem(ctx context.Context, playbookRunID string, sourceChecklistIdx, sourceItemIdx, destChecklistIdx, destItemIdx int) error {
|
||||
createURL := fmt.Sprintf("runs/%s/checklists/move-item", playbookRunID)
|
||||
body := struct {
|
||||
SourceChecklistIdx int `json:"source_checklist_idx"`
|
||||
SourceItemIdx int `json:"source_item_idx"`
|
||||
DestChecklistIdx int `json:"dest_checklist_idx"`
|
||||
DestItemIdx int `json:"dest_item_idx"`
|
||||
}{sourceChecklistIdx, sourceItemIdx, destChecklistIdx, destItemIdx}
|
||||
|
||||
req, err := s.client.newRequest(http.MethodPost, createURL, body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = s.client.do(ctx, req, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdateRetrospective updates the run's retrospective info
|
||||
func (s *PlaybookRunService) UpdateRetrospective(ctx context.Context, playbookRunID, userID string, retroUpdate RetrospectiveUpdate) error {
|
||||
createURL := fmt.Sprintf("runs/%s/retrospective", playbookRunID)
|
||||
req, err := s.client.newRequest(http.MethodPost, createURL, retroUpdate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := s.client.do(ctx, req, nil)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("expected status code %d", http.StatusOK)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// PublishRetrospective publishes the run's retrospective
|
||||
func (s *PlaybookRunService) PublishRetrospective(ctx context.Context, playbookRunID, userID string, retroUpdate RetrospectiveUpdate) error {
|
||||
createURL := fmt.Sprintf("runs/%s/retrospective/publish", playbookRunID)
|
||||
req, err := s.client.newRequest(http.MethodPost, createURL, retroUpdate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := s.client.do(ctx, req, nil)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("expected status code %d", http.StatusOK)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *PlaybookRunService) SetItemAssignee(ctx context.Context, playbookRunID string, checklistIdx int, itemIdx int, assigneeID string) error {
|
||||
createURL := fmt.Sprintf("runs/%s/checklists/%d/item/%d/assignee", playbookRunID, checklistIdx, itemIdx)
|
||||
body := struct {
|
||||
AssigneeID string `json:"assignee_id"`
|
||||
}{assigneeID}
|
||||
|
||||
req, err := s.client.newRequest(http.MethodPut, createURL, body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = s.client.do(ctx, req, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *PlaybookRunService) SetItemCommand(ctx context.Context, playbookRunID string, checklistIdx int, itemIdx int, newCommand string) error {
|
||||
createURL := fmt.Sprintf("runs/%s/checklists/%d/item/%d/command", playbookRunID, checklistIdx, itemIdx)
|
||||
body := struct {
|
||||
Command string `json:"command"`
|
||||
}{newCommand}
|
||||
|
||||
req, err := s.client.newRequest(http.MethodPut, createURL, body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = s.client.do(ctx, req, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *PlaybookRunService) RunItemCommand(ctx context.Context, playbookRunID string, checklistIdx int, itemIdx int) error {
|
||||
createURL := fmt.Sprintf("runs/%s/checklists/%d/item/%d/run", playbookRunID, checklistIdx, itemIdx)
|
||||
|
||||
req, err := s.client.newRequest(http.MethodPost, createURL, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = s.client.do(ctx, req, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *PlaybookRunService) SetItemDueDate(ctx context.Context, playbookRunID string, checklistIdx int, itemIdx int, duedate int64) error {
|
||||
createURL := fmt.Sprintf("runs/%s/checklists/%d/item/%d/duedate", playbookRunID, checklistIdx, itemIdx)
|
||||
body := struct {
|
||||
DueDate int64 `json:"due_date"`
|
||||
}{duedate}
|
||||
|
||||
req, err := s.client.newRequest(http.MethodPut, createURL, body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = s.client.do(ctx, req, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// Get a playbook run.
|
||||
func (s *PlaybookRunService) GetOwners(ctx context.Context) ([]OwnerInfo, error) {
|
||||
req, err := s.client.newRequest(http.MethodGet, "runs/owners", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
owners := make([]OwnerInfo, 0)
|
||||
resp, err := s.client.do(ctx, req, &owners)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
return owners, nil
|
||||
}
|
||||
77
server/playbooks/client/playbook_runs_test.go
Обычный файл
77
server/playbooks/client/playbook_runs_test.go
Обычный файл
@@ -0,0 +1,77 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package client_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
"github.com/mattermost/mattermost-server/v6/server/playbooks/client"
|
||||
)
|
||||
|
||||
func ExamplePlaybookRunService_Get() {
|
||||
ctx := context.Background()
|
||||
|
||||
client4 := model.NewAPIv4Client("http://localhost:8065")
|
||||
client4.Login("test@example.com", "testtest")
|
||||
|
||||
c, err := client.New(client4)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
playbookRunID := "h4n3h7s1qjf5pkis4dn6cuxgwa"
|
||||
playbookRun, err := c.PlaybookRuns.Get(ctx, playbookRunID)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Printf("Playbook Run Name: %s\n", playbookRun.Name)
|
||||
}
|
||||
|
||||
func ExamplePlaybookRunService_List() {
|
||||
ctx := context.Background()
|
||||
|
||||
client4 := model.NewAPIv4Client("http://localhost:8065")
|
||||
_, _, err := client4.Login("test@example.com", "testtest")
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
|
||||
teams, _, err := client4.GetAllTeams("", 0, 1)
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
if len(teams) == 0 {
|
||||
log.Fatal("no teams for this user")
|
||||
}
|
||||
|
||||
c, err := client.New(client4)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
var playbookRuns []client.PlaybookRun
|
||||
for page := 0; ; page++ {
|
||||
result, err := c.PlaybookRuns.List(ctx, page, 100, client.PlaybookRunListOptions{
|
||||
TeamID: teams[0].Id,
|
||||
Sort: client.SortByCreateAt,
|
||||
Direction: client.SortDesc,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
playbookRuns = append(playbookRuns, result.Items...)
|
||||
if !result.HasMore {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for _, playbookRun := range playbookRuns {
|
||||
fmt.Printf("Playbook Run Name: %s\n", playbookRun.Name)
|
||||
}
|
||||
}
|
||||
269
server/playbooks/client/playbooks.go
Обычный файл
269
server/playbooks/client/playbooks.go
Обычный файл
@@ -0,0 +1,269 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// PlaybooksService handles communication with the playbook related
|
||||
// methods of the Playbook API.
|
||||
type PlaybooksService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// Get a playbook.
|
||||
func (s *PlaybooksService) Get(ctx context.Context, playbookID string) (*Playbook, error) {
|
||||
playbookURL := fmt.Sprintf("playbooks/%s", playbookID)
|
||||
req, err := s.client.newRequest(http.MethodGet, playbookURL, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
playbook := new(Playbook)
|
||||
resp, err := s.client.do(ctx, req, playbook)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
return playbook, nil
|
||||
}
|
||||
|
||||
// List the playbooks.
|
||||
func (s *PlaybooksService) List(ctx context.Context, teamId string, page, perPage int, opts PlaybookListOptions) (*GetPlaybooksResults, error) {
|
||||
playbookURL := "playbooks"
|
||||
playbookURL, err := addOption(playbookURL, "team_id", teamId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to build options: %w", err)
|
||||
}
|
||||
|
||||
playbookURL, err = addPaginationOptions(playbookURL, page, perPage)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to build pagination options: %w", err)
|
||||
}
|
||||
|
||||
playbookURL, err = addOptions(playbookURL, opts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to build options: %w", err)
|
||||
}
|
||||
|
||||
req, err := s.client.newRequest(http.MethodGet, playbookURL, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to build request: %w", err)
|
||||
}
|
||||
|
||||
result := &GetPlaybooksResults{}
|
||||
resp, err := s.client.do(ctx, req, result)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute request: %w", err)
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Create a playbook. Returns the id of the newly created playbook
|
||||
func (s *PlaybooksService) Create(ctx context.Context, opts PlaybookCreateOptions) (string, error) {
|
||||
// For ease of use set the default if not specificed so it doesn't just error
|
||||
if opts.ReminderTimerDefaultSeconds == 0 {
|
||||
opts.ReminderTimerDefaultSeconds = 86400
|
||||
}
|
||||
|
||||
playbookURL := "playbooks"
|
||||
req, err := s.client.newRequest(http.MethodPost, playbookURL, opts)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var result struct {
|
||||
ID string `json:"id"`
|
||||
}
|
||||
resp, err := s.client.do(ctx, req, &result)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusCreated {
|
||||
return "", fmt.Errorf("expected status code %d", http.StatusCreated)
|
||||
}
|
||||
|
||||
return result.ID, nil
|
||||
}
|
||||
|
||||
func (s *PlaybooksService) Update(ctx context.Context, playbook Playbook) error {
|
||||
updateURL := fmt.Sprintf("playbooks/%s", playbook.ID)
|
||||
req, err := s.client.newRequest(http.MethodPut, updateURL, playbook)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = s.client.do(ctx, req, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *PlaybooksService) Archive(ctx context.Context, playbookID string) error {
|
||||
updateURL := fmt.Sprintf("playbooks/%s", playbookID)
|
||||
req, err := s.client.newRequest(http.MethodDelete, updateURL, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = s.client.do(ctx, req, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *PlaybooksService) Export(ctx context.Context, playbookID string) ([]byte, error) {
|
||||
url := fmt.Sprintf("playbooks/%s/export", playbookID)
|
||||
req, err := s.client.newRequest(http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := s.client.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
result, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("expected status code %d", http.StatusOK)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Duplicate a playbook. Returns the id of the newly created playbook
|
||||
func (s *PlaybooksService) Duplicate(ctx context.Context, playbookID string) (string, error) {
|
||||
url := fmt.Sprintf("playbooks/%s/duplicate", playbookID)
|
||||
req, err := s.client.newRequest(http.MethodPost, url, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var result struct {
|
||||
ID string `json:"id"`
|
||||
}
|
||||
resp, err := s.client.do(ctx, req, &result)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusCreated {
|
||||
return "", fmt.Errorf("expected status code %d", http.StatusCreated)
|
||||
}
|
||||
|
||||
return result.ID, nil
|
||||
}
|
||||
|
||||
// Imports a playbook. Returns the id of the newly created playbook
|
||||
func (s *PlaybooksService) Import(ctx context.Context, toImport []byte, team string) (string, error) {
|
||||
url := "playbooks/import?team_id=" + team
|
||||
u, err := s.client.BaseURL.Parse(buildAPIURL(url))
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "invalid endpoint %s", url)
|
||||
}
|
||||
req, err := http.NewRequest(http.MethodPost, u.String(), bytes.NewReader(toImport))
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "failed to create http request for import")
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
var result struct {
|
||||
ID string `json:"id"`
|
||||
}
|
||||
resp, err := s.client.do(ctx, req, &result)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusCreated {
|
||||
return "", fmt.Errorf("expected status code %d", http.StatusCreated)
|
||||
}
|
||||
|
||||
return result.ID, nil
|
||||
}
|
||||
|
||||
func (s *PlaybooksService) Stats(ctx context.Context, playbookID string) (*PlaybookStats, error) {
|
||||
playbookStatsURL := fmt.Sprintf("stats/playbook?playbook_id=%s", playbookID)
|
||||
req, err := s.client.newRequest(http.MethodGet, playbookStatsURL, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stats := new(PlaybookStats)
|
||||
resp, err := s.client.do(ctx, req, stats)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
func (s *PlaybooksService) AutoFollow(ctx context.Context, playbookID string, userID string) error {
|
||||
followsURL := fmt.Sprintf("playbooks/%s/autofollows/%s", playbookID, userID)
|
||||
req, err := s.client.newRequest(http.MethodPut, followsURL, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = s.client.do(ctx, req, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *PlaybooksService) AutoUnfollow(ctx context.Context, playbookID string, userID string) error {
|
||||
followsURL := fmt.Sprintf("playbooks/%s/autofollows/%s", playbookID, userID)
|
||||
req, err := s.client.newRequest(http.MethodDelete, followsURL, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = s.client.do(ctx, req, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *PlaybooksService) GetAutoFollows(ctx context.Context, playbookID string) ([]string, error) {
|
||||
autofollowsURL := fmt.Sprintf("playbooks/%s/autofollows", playbookID)
|
||||
req, err := s.client.newRequest(http.MethodGet, autofollowsURL, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var followers []string
|
||||
resp, err := s.client.do(ctx, req, &followers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
return followers, nil
|
||||
}
|
||||
76
server/playbooks/client/playbooks_test.go
Обычный файл
76
server/playbooks/client/playbooks_test.go
Обычный файл
@@ -0,0 +1,76 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package client_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
"github.com/mattermost/mattermost-server/v6/server/playbooks/client"
|
||||
)
|
||||
|
||||
func ExamplePlaybooksService_Get() {
|
||||
ctx := context.Background()
|
||||
|
||||
client4 := model.NewAPIv4Client("http://localhost:8065")
|
||||
client4.Login("test@example.com", "testtest")
|
||||
|
||||
c, err := client.New(client4)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
playbookID := "h4n3h7s1qjf5pkis4dn6cuxgwa"
|
||||
playbook, err := c.Playbooks.Get(ctx, playbookID)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Printf("Playbook Name: %s\n", playbook.Title)
|
||||
}
|
||||
|
||||
func ExamplePlaybooksService_List() {
|
||||
ctx := context.Background()
|
||||
|
||||
client4 := model.NewAPIv4Client("http://localhost:8065")
|
||||
_, _, err := client4.Login("test@example.com", "testtest")
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
|
||||
teams, _, err := client4.GetAllTeams("", 0, 1)
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
if len(teams) == 0 {
|
||||
log.Fatal("no teams for this user")
|
||||
}
|
||||
|
||||
c, err := client.New(client4)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
var playbooks []client.Playbook
|
||||
for page := 0; ; page++ {
|
||||
result, err := c.Playbooks.List(ctx, teams[0].Id, page, 100, client.PlaybookListOptions{
|
||||
Sort: client.SortByCreateAt,
|
||||
Direction: client.SortDesc,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
playbooks = append(playbooks, result.Items...)
|
||||
if !result.HasMore {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for _, playbook := range playbooks {
|
||||
fmt.Printf("Playbook Name: %s\n", playbook.Title)
|
||||
}
|
||||
}
|
||||
8
server/playbooks/client/reminder.go
Обычный файл
8
server/playbooks/client/reminder.go
Обычный файл
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package client
|
||||
|
||||
type ReminderResetPayload struct {
|
||||
NewReminderSeconds int `json:"new_reminder_seconds"`
|
||||
}
|
||||
36
server/playbooks/client/reminders.go
Обычный файл
36
server/playbooks/client/reminders.go
Обычный файл
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type RemindersService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
func (s *RemindersService) Reset(ctx context.Context, playbookRunID string, payload ReminderResetPayload) error {
|
||||
resetURL := fmt.Sprintf("runs/%s/reminder", playbookRunID)
|
||||
|
||||
req, err := s.client.newRequest(http.MethodPost, resetURL, payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := s.client.do(ctx, req, ioutil.Discard)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusNoContent {
|
||||
return fmt.Errorf("expected status code %d", http.StatusNoContent)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
55
server/playbooks/client/settings.go
Обычный файл
55
server/playbooks/client/settings.go
Обычный файл
@@ -0,0 +1,55 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type GlobalSettings struct {
|
||||
// EnableExperimentalFeatures is a read-only field set to true when experimental features
|
||||
// are enabled. Changing this field requires access to the system console plugin
|
||||
// configuration.
|
||||
EnableExperimentalFeatures bool `json:"enable_experimental_features"`
|
||||
}
|
||||
|
||||
// SettingsService handles communication with the settings related methods.
|
||||
type SettingsService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// Get the configured settings.
|
||||
func (s *SettingsService) Get(ctx context.Context) (*GlobalSettings, error) {
|
||||
settingsURL := "settings"
|
||||
req, err := s.client.newRequest(http.MethodGet, settingsURL, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
settings := new(GlobalSettings)
|
||||
resp, err := s.client.do(ctx, req, settings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
return settings, nil
|
||||
}
|
||||
|
||||
// Update the configured settings.
|
||||
func (s *SettingsService) Update(ctx context.Context, settings GlobalSettings) error {
|
||||
settingsURL := "settings"
|
||||
req, err := s.client.newRequest(http.MethodPut, settingsURL, settings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = s.client.do(ctx, req, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
38
server/playbooks/client/stats.go
Обычный файл
38
server/playbooks/client/stats.go
Обычный файл
@@ -0,0 +1,38 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// StatsService handles communication with the stats related methods.
|
||||
type StatsService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// PlaybookSiteStats holds the data that we want to expose in system console
|
||||
type PlaybookSiteStats struct {
|
||||
TotalPlaybooks int `json:"total_playbooks"`
|
||||
TotalPlaybookRuns int `json:"total_playbook_runs"`
|
||||
}
|
||||
|
||||
// Get the stats that should be displayed in system console.
|
||||
func (s *StatsService) GetSiteStats(ctx context.Context) (*PlaybookSiteStats, error) {
|
||||
statsURL := "stats/site"
|
||||
req, err := s.client.newRequest(http.MethodGet, statsURL, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stats := new(PlaybookSiteStats)
|
||||
resp, err := s.client.do(ctx, req, stats)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
49
server/playbooks/client/telemetry.go
Обычный файл
49
server/playbooks/client/telemetry.go
Обычный файл
@@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type TelemetryService struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
func (s *TelemetryService) CreateEvent(ctx context.Context, name string, eventType string, properties map[string]interface{}) error {
|
||||
|
||||
payload := struct {
|
||||
Type string
|
||||
Name string
|
||||
Properties map[string]interface{}
|
||||
}{
|
||||
Type: eventType,
|
||||
Name: name,
|
||||
Properties: properties,
|
||||
}
|
||||
|
||||
req, err := s.client.newRequest(http.MethodPost, "telemetry", payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := s.client.do(ctx, req, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusNoContent {
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return fmt.Errorf("expected status code %d, got %d: %s", http.StatusNoContent, resp.StatusCode, body)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
7
server/playbooks/client/unexport_test.go
Обычный файл
7
server/playbooks/client/unexport_test.go
Обычный файл
@@ -0,0 +1,7 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package client
|
||||
|
||||
var BuildAPIURL = buildAPIURL
|
||||
var NewClient = newClient
|
||||
Ссылка в новой задаче
Block a user