diff --git a/build/manifest/Gopkg.lock b/build/manifest/Gopkg.lock index e6431a8..c827c7c 100644 --- a/build/manifest/Gopkg.lock +++ b/build/manifest/Gopkg.lock @@ -1,6 +1,14 @@ # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. +[[projects]] + digest = "1:705c40022f5c03bf96ffeb6477858d88565064485a513abcd0f11a0911546cb6" + name = "github.com/blang/semver" + packages = ["."] + pruneopts = "UT" + revision = "2ee87856327ba09384cabd113bc6b5d174e9ec0f" + version = "v3.5.1" + [[projects]] branch = "master" digest = "1:bc36a17a513f15717b5fa3dcfd666f5ddb6fd3db06f5f2834ac2f5979d4f5070" @@ -10,7 +18,7 @@ revision = "5ed622c449da6d44c3c8329331ff47a9e5844f71" [[projects]] - digest = "1:771649e04a49766e04f498731699e62874ffa2439a071294fde36d61b2db0685" + digest = "1:1cebd7208d10c6f20d5fd71c9c7062fea74524842db93fec2993fb5ea4975c73" name = "github.com/mattermost/mattermost-server" packages = [ "mlog", @@ -19,8 +27,8 @@ "utils/markdown", ] pruneopts = "UT" - revision = "d5b613cb1bbdaa856fa126e7102d94783b9e80b6" - version = "v5.4.0" + revision = "0c1207215852a8726c3f09dea157d597fec368df" + version = "v5.6.0" [[projects]] digest = "1:07140002dbf37da92090f731b46fa47be4820b82fe5c14a035203b0e813d0ec2" diff --git a/build/manifest/Gopkg.toml b/build/manifest/Gopkg.toml index ee26376..c6309c7 100644 --- a/build/manifest/Gopkg.toml +++ b/build/manifest/Gopkg.toml @@ -4,7 +4,7 @@ [[constraint]] name = "github.com/mattermost/mattermost-server" - version = "~5.4.0" + version = "~5.6.0" [[constraint]] name = "github.com/pkg/errors" diff --git a/build/manifest/vendor/github.com/blang/semver/.travis.yml b/build/manifest/vendor/github.com/blang/semver/.travis.yml new file mode 100644 index 0000000..102fb9a --- /dev/null +++ b/build/manifest/vendor/github.com/blang/semver/.travis.yml @@ -0,0 +1,21 @@ +language: go +matrix: + include: + - go: 1.4.3 + - go: 1.5.4 + - go: 1.6.3 + - go: 1.7 + - go: tip + allow_failures: + - go: tip +install: +- go get golang.org/x/tools/cmd/cover +- go get github.com/mattn/goveralls +script: +- echo "Test and track coverage" ; $HOME/gopath/bin/goveralls -package "." -service=travis-ci + -repotoken $COVERALLS_TOKEN +- echo "Build examples" ; cd examples && go build +- echo "Check if gofmt'd" ; diff -u <(echo -n) <(gofmt -d -s .) +env: + global: + secure: HroGEAUQpVq9zX1b1VIkraLiywhGbzvNnTZq2TMxgK7JHP8xqNplAeF1izrR2i4QLL9nsY+9WtYss4QuPvEtZcVHUobw6XnL6radF7jS1LgfYZ9Y7oF+zogZ2I5QUMRLGA7rcxQ05s7mKq3XZQfeqaNts4bms/eZRefWuaFZbkw= diff --git a/build/manifest/vendor/github.com/blang/semver/LICENSE b/build/manifest/vendor/github.com/blang/semver/LICENSE new file mode 100644 index 0000000..5ba5c86 --- /dev/null +++ b/build/manifest/vendor/github.com/blang/semver/LICENSE @@ -0,0 +1,22 @@ +The MIT License + +Copyright (c) 2014 Benedikt Lang + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/build/manifest/vendor/github.com/blang/semver/README.md b/build/manifest/vendor/github.com/blang/semver/README.md new file mode 100644 index 0000000..08b2e4a --- /dev/null +++ b/build/manifest/vendor/github.com/blang/semver/README.md @@ -0,0 +1,194 @@ +semver for golang [![Build Status](https://travis-ci.org/blang/semver.svg?branch=master)](https://travis-ci.org/blang/semver) [![GoDoc](https://godoc.org/github.com/blang/semver?status.png)](https://godoc.org/github.com/blang/semver) [![Coverage Status](https://img.shields.io/coveralls/blang/semver.svg)](https://coveralls.io/r/blang/semver?branch=master) +====== + +semver is a [Semantic Versioning](http://semver.org/) library written in golang. It fully covers spec version `2.0.0`. + +Usage +----- +```bash +$ go get github.com/blang/semver +``` +Note: Always vendor your dependencies or fix on a specific version tag. + +```go +import github.com/blang/semver +v1, err := semver.Make("1.0.0-beta") +v2, err := semver.Make("2.0.0-beta") +v1.Compare(v2) +``` + +Also check the [GoDocs](http://godoc.org/github.com/blang/semver). + +Why should I use this lib? +----- + +- Fully spec compatible +- No reflection +- No regex +- Fully tested (Coverage >99%) +- Readable parsing/validation errors +- Fast (See [Benchmarks](#benchmarks)) +- Only Stdlib +- Uses values instead of pointers +- Many features, see below + + +Features +----- + +- Parsing and validation at all levels +- Comparator-like comparisons +- Compare Helper Methods +- InPlace manipulation +- Ranges `>=1.0.0 <2.0.0 || >=3.0.0 !3.0.1-beta.1` +- Wildcards `>=1.x`, `<=2.5.x` +- Sortable (implements sort.Interface) +- database/sql compatible (sql.Scanner/Valuer) +- encoding/json compatible (json.Marshaler/Unmarshaler) + +Ranges +------ + +A `Range` is a set of conditions which specify which versions satisfy the range. + +A condition is composed of an operator and a version. The supported operators are: + +- `<1.0.0` Less than `1.0.0` +- `<=1.0.0` Less than or equal to `1.0.0` +- `>1.0.0` Greater than `1.0.0` +- `>=1.0.0` Greater than or equal to `1.0.0` +- `1.0.0`, `=1.0.0`, `==1.0.0` Equal to `1.0.0` +- `!1.0.0`, `!=1.0.0` Not equal to `1.0.0`. Excludes version `1.0.0`. + +Note that spaces between the operator and the version will be gracefully tolerated. + +A `Range` can link multiple `Ranges` separated by space: + +Ranges can be linked by logical AND: + + - `>1.0.0 <2.0.0` would match between both ranges, so `1.1.1` and `1.8.7` but not `1.0.0` or `2.0.0` + - `>1.0.0 <3.0.0 !2.0.3-beta.2` would match every version between `1.0.0` and `3.0.0` except `2.0.3-beta.2` + +Ranges can also be linked by logical OR: + + - `<2.0.0 || >=3.0.0` would match `1.x.x` and `3.x.x` but not `2.x.x` + +AND has a higher precedence than OR. It's not possible to use brackets. + +Ranges can be combined by both AND and OR + + - `>1.0.0 <2.0.0 || >3.0.0 !4.2.1` would match `1.2.3`, `1.9.9`, `3.1.1`, but not `4.2.1`, `2.1.1` + +Range usage: + +``` +v, err := semver.Parse("1.2.3") +range, err := semver.ParseRange(">1.0.0 <2.0.0 || >=3.0.0") +if range(v) { + //valid +} + +``` + +Example +----- + +Have a look at full examples in [examples/main.go](examples/main.go) + +```go +import github.com/blang/semver + +v, err := semver.Make("0.0.1-alpha.preview+123.github") +fmt.Printf("Major: %d\n", v.Major) +fmt.Printf("Minor: %d\n", v.Minor) +fmt.Printf("Patch: %d\n", v.Patch) +fmt.Printf("Pre: %s\n", v.Pre) +fmt.Printf("Build: %s\n", v.Build) + +// Prerelease versions array +if len(v.Pre) > 0 { + fmt.Println("Prerelease versions:") + for i, pre := range v.Pre { + fmt.Printf("%d: %q\n", i, pre) + } +} + +// Build meta data array +if len(v.Build) > 0 { + fmt.Println("Build meta data:") + for i, build := range v.Build { + fmt.Printf("%d: %q\n", i, build) + } +} + +v001, err := semver.Make("0.0.1") +// Compare using helpers: v.GT(v2), v.LT, v.GTE, v.LTE +v001.GT(v) == true +v.LT(v001) == true +v.GTE(v) == true +v.LTE(v) == true + +// Or use v.Compare(v2) for comparisons (-1, 0, 1): +v001.Compare(v) == 1 +v.Compare(v001) == -1 +v.Compare(v) == 0 + +// Manipulate Version in place: +v.Pre[0], err = semver.NewPRVersion("beta") +if err != nil { + fmt.Printf("Error parsing pre release version: %q", err) +} + +fmt.Println("\nValidate versions:") +v.Build[0] = "?" + +err = v.Validate() +if err != nil { + fmt.Printf("Validation failed: %s\n", err) +} +``` + + +Benchmarks +----- + + BenchmarkParseSimple-4 5000000 390 ns/op 48 B/op 1 allocs/op + BenchmarkParseComplex-4 1000000 1813 ns/op 256 B/op 7 allocs/op + BenchmarkParseAverage-4 1000000 1171 ns/op 163 B/op 4 allocs/op + BenchmarkStringSimple-4 20000000 119 ns/op 16 B/op 1 allocs/op + BenchmarkStringLarger-4 10000000 206 ns/op 32 B/op 2 allocs/op + BenchmarkStringComplex-4 5000000 324 ns/op 80 B/op 3 allocs/op + BenchmarkStringAverage-4 5000000 273 ns/op 53 B/op 2 allocs/op + BenchmarkValidateSimple-4 200000000 9.33 ns/op 0 B/op 0 allocs/op + BenchmarkValidateComplex-4 3000000 469 ns/op 0 B/op 0 allocs/op + BenchmarkValidateAverage-4 5000000 256 ns/op 0 B/op 0 allocs/op + BenchmarkCompareSimple-4 100000000 11.8 ns/op 0 B/op 0 allocs/op + BenchmarkCompareComplex-4 50000000 30.8 ns/op 0 B/op 0 allocs/op + BenchmarkCompareAverage-4 30000000 41.5 ns/op 0 B/op 0 allocs/op + BenchmarkSort-4 3000000 419 ns/op 256 B/op 2 allocs/op + BenchmarkRangeParseSimple-4 2000000 850 ns/op 192 B/op 5 allocs/op + BenchmarkRangeParseAverage-4 1000000 1677 ns/op 400 B/op 10 allocs/op + BenchmarkRangeParseComplex-4 300000 5214 ns/op 1440 B/op 30 allocs/op + BenchmarkRangeMatchSimple-4 50000000 25.6 ns/op 0 B/op 0 allocs/op + BenchmarkRangeMatchAverage-4 30000000 56.4 ns/op 0 B/op 0 allocs/op + BenchmarkRangeMatchComplex-4 10000000 153 ns/op 0 B/op 0 allocs/op + +See benchmark cases at [semver_test.go](semver_test.go) + + +Motivation +----- + +I simply couldn't find any lib supporting the full spec. Others were just wrong or used reflection and regex which i don't like. + + +Contribution +----- + +Feel free to make a pull request. For bigger changes create a issue first to discuss about it. + + +License +----- + +See [LICENSE](LICENSE) file. diff --git a/build/manifest/vendor/github.com/blang/semver/json.go b/build/manifest/vendor/github.com/blang/semver/json.go new file mode 100644 index 0000000..a74bf7c --- /dev/null +++ b/build/manifest/vendor/github.com/blang/semver/json.go @@ -0,0 +1,23 @@ +package semver + +import ( + "encoding/json" +) + +// MarshalJSON implements the encoding/json.Marshaler interface. +func (v Version) MarshalJSON() ([]byte, error) { + return json.Marshal(v.String()) +} + +// UnmarshalJSON implements the encoding/json.Unmarshaler interface. +func (v *Version) UnmarshalJSON(data []byte) (err error) { + var versionString string + + if err = json.Unmarshal(data, &versionString); err != nil { + return + } + + *v, err = Parse(versionString) + + return +} diff --git a/build/manifest/vendor/github.com/blang/semver/package.json b/build/manifest/vendor/github.com/blang/semver/package.json new file mode 100644 index 0000000..1cf8ebd --- /dev/null +++ b/build/manifest/vendor/github.com/blang/semver/package.json @@ -0,0 +1,17 @@ +{ + "author": "blang", + "bugs": { + "URL": "https://github.com/blang/semver/issues", + "url": "https://github.com/blang/semver/issues" + }, + "gx": { + "dvcsimport": "github.com/blang/semver" + }, + "gxVersion": "0.10.0", + "language": "go", + "license": "MIT", + "name": "semver", + "releaseCmd": "git commit -a -m \"gx publish $VERSION\"", + "version": "3.5.1" +} + diff --git a/build/manifest/vendor/github.com/blang/semver/range.go b/build/manifest/vendor/github.com/blang/semver/range.go new file mode 100644 index 0000000..fca406d --- /dev/null +++ b/build/manifest/vendor/github.com/blang/semver/range.go @@ -0,0 +1,416 @@ +package semver + +import ( + "fmt" + "strconv" + "strings" + "unicode" +) + +type wildcardType int + +const ( + noneWildcard wildcardType = iota + majorWildcard wildcardType = 1 + minorWildcard wildcardType = 2 + patchWildcard wildcardType = 3 +) + +func wildcardTypefromInt(i int) wildcardType { + switch i { + case 1: + return majorWildcard + case 2: + return minorWildcard + case 3: + return patchWildcard + default: + return noneWildcard + } +} + +type comparator func(Version, Version) bool + +var ( + compEQ comparator = func(v1 Version, v2 Version) bool { + return v1.Compare(v2) == 0 + } + compNE = func(v1 Version, v2 Version) bool { + return v1.Compare(v2) != 0 + } + compGT = func(v1 Version, v2 Version) bool { + return v1.Compare(v2) == 1 + } + compGE = func(v1 Version, v2 Version) bool { + return v1.Compare(v2) >= 0 + } + compLT = func(v1 Version, v2 Version) bool { + return v1.Compare(v2) == -1 + } + compLE = func(v1 Version, v2 Version) bool { + return v1.Compare(v2) <= 0 + } +) + +type versionRange struct { + v Version + c comparator +} + +// rangeFunc creates a Range from the given versionRange. +func (vr *versionRange) rangeFunc() Range { + return Range(func(v Version) bool { + return vr.c(v, vr.v) + }) +} + +// Range represents a range of versions. +// A Range can be used to check if a Version satisfies it: +// +// range, err := semver.ParseRange(">1.0.0 <2.0.0") +// range(semver.MustParse("1.1.1") // returns true +type Range func(Version) bool + +// OR combines the existing Range with another Range using logical OR. +func (rf Range) OR(f Range) Range { + return Range(func(v Version) bool { + return rf(v) || f(v) + }) +} + +// AND combines the existing Range with another Range using logical AND. +func (rf Range) AND(f Range) Range { + return Range(func(v Version) bool { + return rf(v) && f(v) + }) +} + +// ParseRange parses a range and returns a Range. +// If the range could not be parsed an error is returned. +// +// Valid ranges are: +// - "<1.0.0" +// - "<=1.0.0" +// - ">1.0.0" +// - ">=1.0.0" +// - "1.0.0", "=1.0.0", "==1.0.0" +// - "!1.0.0", "!=1.0.0" +// +// A Range can consist of multiple ranges separated by space: +// Ranges can be linked by logical AND: +// - ">1.0.0 <2.0.0" would match between both ranges, so "1.1.1" and "1.8.7" but not "1.0.0" or "2.0.0" +// - ">1.0.0 <3.0.0 !2.0.3-beta.2" would match every version between 1.0.0 and 3.0.0 except 2.0.3-beta.2 +// +// Ranges can also be linked by logical OR: +// - "<2.0.0 || >=3.0.0" would match "1.x.x" and "3.x.x" but not "2.x.x" +// +// AND has a higher precedence than OR. It's not possible to use brackets. +// +// Ranges can be combined by both AND and OR +// +// - `>1.0.0 <2.0.0 || >3.0.0 !4.2.1` would match `1.2.3`, `1.9.9`, `3.1.1`, but not `4.2.1`, `2.1.1` +func ParseRange(s string) (Range, error) { + parts := splitAndTrim(s) + orParts, err := splitORParts(parts) + if err != nil { + return nil, err + } + expandedParts, err := expandWildcardVersion(orParts) + if err != nil { + return nil, err + } + var orFn Range + for _, p := range expandedParts { + var andFn Range + for _, ap := range p { + opStr, vStr, err := splitComparatorVersion(ap) + if err != nil { + return nil, err + } + vr, err := buildVersionRange(opStr, vStr) + if err != nil { + return nil, fmt.Errorf("Could not parse Range %q: %s", ap, err) + } + rf := vr.rangeFunc() + + // Set function + if andFn == nil { + andFn = rf + } else { // Combine with existing function + andFn = andFn.AND(rf) + } + } + if orFn == nil { + orFn = andFn + } else { + orFn = orFn.OR(andFn) + } + + } + return orFn, nil +} + +// splitORParts splits the already cleaned parts by '||'. +// Checks for invalid positions of the operator and returns an +// error if found. +func splitORParts(parts []string) ([][]string, error) { + var ORparts [][]string + last := 0 + for i, p := range parts { + if p == "||" { + if i == 0 { + return nil, fmt.Errorf("First element in range is '||'") + } + ORparts = append(ORparts, parts[last:i]) + last = i + 1 + } + } + if last == len(parts) { + return nil, fmt.Errorf("Last element in range is '||'") + } + ORparts = append(ORparts, parts[last:]) + return ORparts, nil +} + +// buildVersionRange takes a slice of 2: operator and version +// and builds a versionRange, otherwise an error. +func buildVersionRange(opStr, vStr string) (*versionRange, error) { + c := parseComparator(opStr) + if c == nil { + return nil, fmt.Errorf("Could not parse comparator %q in %q", opStr, strings.Join([]string{opStr, vStr}, "")) + } + v, err := Parse(vStr) + if err != nil { + return nil, fmt.Errorf("Could not parse version %q in %q: %s", vStr, strings.Join([]string{opStr, vStr}, ""), err) + } + + return &versionRange{ + v: v, + c: c, + }, nil + +} + +// inArray checks if a byte is contained in an array of bytes +func inArray(s byte, list []byte) bool { + for _, el := range list { + if el == s { + return true + } + } + return false +} + +// splitAndTrim splits a range string by spaces and cleans whitespaces +func splitAndTrim(s string) (result []string) { + last := 0 + var lastChar byte + excludeFromSplit := []byte{'>', '<', '='} + for i := 0; i < len(s); i++ { + if s[i] == ' ' && !inArray(lastChar, excludeFromSplit) { + if last < i-1 { + result = append(result, s[last:i]) + } + last = i + 1 + } else if s[i] != ' ' { + lastChar = s[i] + } + } + if last < len(s)-1 { + result = append(result, s[last:]) + } + + for i, v := range result { + result[i] = strings.Replace(v, " ", "", -1) + } + + // parts := strings.Split(s, " ") + // for _, x := range parts { + // if s := strings.TrimSpace(x); len(s) != 0 { + // result = append(result, s) + // } + // } + return +} + +// splitComparatorVersion splits the comparator from the version. +// Input must be free of leading or trailing spaces. +func splitComparatorVersion(s string) (string, string, error) { + i := strings.IndexFunc(s, unicode.IsDigit) + if i == -1 { + return "", "", fmt.Errorf("Could not get version from string: %q", s) + } + return strings.TrimSpace(s[0:i]), s[i:], nil +} + +// getWildcardType will return the type of wildcard that the +// passed version contains +func getWildcardType(vStr string) wildcardType { + parts := strings.Split(vStr, ".") + nparts := len(parts) + wildcard := parts[nparts-1] + + possibleWildcardType := wildcardTypefromInt(nparts) + if wildcard == "x" { + return possibleWildcardType + } + + return noneWildcard +} + +// createVersionFromWildcard will convert a wildcard version +// into a regular version, replacing 'x's with '0's, handling +// special cases like '1.x.x' and '1.x' +func createVersionFromWildcard(vStr string) string { + // handle 1.x.x + vStr2 := strings.Replace(vStr, ".x.x", ".x", 1) + vStr2 = strings.Replace(vStr2, ".x", ".0", 1) + parts := strings.Split(vStr2, ".") + + // handle 1.x + if len(parts) == 2 { + return vStr2 + ".0" + } + + return vStr2 +} + +// incrementMajorVersion will increment the major version +// of the passed version +func incrementMajorVersion(vStr string) (string, error) { + parts := strings.Split(vStr, ".") + i, err := strconv.Atoi(parts[0]) + if err != nil { + return "", err + } + parts[0] = strconv.Itoa(i + 1) + + return strings.Join(parts, "."), nil +} + +// incrementMajorVersion will increment the minor version +// of the passed version +func incrementMinorVersion(vStr string) (string, error) { + parts := strings.Split(vStr, ".") + i, err := strconv.Atoi(parts[1]) + if err != nil { + return "", err + } + parts[1] = strconv.Itoa(i + 1) + + return strings.Join(parts, "."), nil +} + +// expandWildcardVersion will expand wildcards inside versions +// following these rules: +// +// * when dealing with patch wildcards: +// >= 1.2.x will become >= 1.2.0 +// <= 1.2.x will become < 1.3.0 +// > 1.2.x will become >= 1.3.0 +// < 1.2.x will become < 1.2.0 +// != 1.2.x will become < 1.2.0 >= 1.3.0 +// +// * when dealing with minor wildcards: +// >= 1.x will become >= 1.0.0 +// <= 1.x will become < 2.0.0 +// > 1.x will become >= 2.0.0 +// < 1.0 will become < 1.0.0 +// != 1.x will become < 1.0.0 >= 2.0.0 +// +// * when dealing with wildcards without +// version operator: +// 1.2.x will become >= 1.2.0 < 1.3.0 +// 1.x will become >= 1.0.0 < 2.0.0 +func expandWildcardVersion(parts [][]string) ([][]string, error) { + var expandedParts [][]string + for _, p := range parts { + var newParts []string + for _, ap := range p { + if strings.Index(ap, "x") != -1 { + opStr, vStr, err := splitComparatorVersion(ap) + if err != nil { + return nil, err + } + + versionWildcardType := getWildcardType(vStr) + flatVersion := createVersionFromWildcard(vStr) + + var resultOperator string + var shouldIncrementVersion bool + switch opStr { + case ">": + resultOperator = ">=" + shouldIncrementVersion = true + case ">=": + resultOperator = ">=" + case "<": + resultOperator = "<" + case "<=": + resultOperator = "<" + shouldIncrementVersion = true + case "", "=", "==": + newParts = append(newParts, ">="+flatVersion) + resultOperator = "<" + shouldIncrementVersion = true + case "!=", "!": + newParts = append(newParts, "<"+flatVersion) + resultOperator = ">=" + shouldIncrementVersion = true + } + + var resultVersion string + if shouldIncrementVersion { + switch versionWildcardType { + case patchWildcard: + resultVersion, _ = incrementMinorVersion(flatVersion) + case minorWildcard: + resultVersion, _ = incrementMajorVersion(flatVersion) + } + } else { + resultVersion = flatVersion + } + + ap = resultOperator + resultVersion + } + newParts = append(newParts, ap) + } + expandedParts = append(expandedParts, newParts) + } + + return expandedParts, nil +} + +func parseComparator(s string) comparator { + switch s { + case "==": + fallthrough + case "": + fallthrough + case "=": + return compEQ + case ">": + return compGT + case ">=": + return compGE + case "<": + return compLT + case "<=": + return compLE + case "!": + fallthrough + case "!=": + return compNE + } + + return nil +} + +// MustParseRange is like ParseRange but panics if the range cannot be parsed. +func MustParseRange(s string) Range { + r, err := ParseRange(s) + if err != nil { + panic(`semver: ParseRange(` + s + `): ` + err.Error()) + } + return r +} diff --git a/build/manifest/vendor/github.com/blang/semver/semver.go b/build/manifest/vendor/github.com/blang/semver/semver.go new file mode 100644 index 0000000..8ee0842 --- /dev/null +++ b/build/manifest/vendor/github.com/blang/semver/semver.go @@ -0,0 +1,418 @@ +package semver + +import ( + "errors" + "fmt" + "strconv" + "strings" +) + +const ( + numbers string = "0123456789" + alphas = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-" + alphanum = alphas + numbers +) + +// SpecVersion is the latest fully supported spec version of semver +var SpecVersion = Version{ + Major: 2, + Minor: 0, + Patch: 0, +} + +// Version represents a semver compatible version +type Version struct { + Major uint64 + Minor uint64 + Patch uint64 + Pre []PRVersion + Build []string //No Precendence +} + +// Version to string +func (v Version) String() string { + b := make([]byte, 0, 5) + b = strconv.AppendUint(b, v.Major, 10) + b = append(b, '.') + b = strconv.AppendUint(b, v.Minor, 10) + b = append(b, '.') + b = strconv.AppendUint(b, v.Patch, 10) + + if len(v.Pre) > 0 { + b = append(b, '-') + b = append(b, v.Pre[0].String()...) + + for _, pre := range v.Pre[1:] { + b = append(b, '.') + b = append(b, pre.String()...) + } + } + + if len(v.Build) > 0 { + b = append(b, '+') + b = append(b, v.Build[0]...) + + for _, build := range v.Build[1:] { + b = append(b, '.') + b = append(b, build...) + } + } + + return string(b) +} + +// Equals checks if v is equal to o. +func (v Version) Equals(o Version) bool { + return (v.Compare(o) == 0) +} + +// EQ checks if v is equal to o. +func (v Version) EQ(o Version) bool { + return (v.Compare(o) == 0) +} + +// NE checks if v is not equal to o. +func (v Version) NE(o Version) bool { + return (v.Compare(o) != 0) +} + +// GT checks if v is greater than o. +func (v Version) GT(o Version) bool { + return (v.Compare(o) == 1) +} + +// GTE checks if v is greater than or equal to o. +func (v Version) GTE(o Version) bool { + return (v.Compare(o) >= 0) +} + +// GE checks if v is greater than or equal to o. +func (v Version) GE(o Version) bool { + return (v.Compare(o) >= 0) +} + +// LT checks if v is less than o. +func (v Version) LT(o Version) bool { + return (v.Compare(o) == -1) +} + +// LTE checks if v is less than or equal to o. +func (v Version) LTE(o Version) bool { + return (v.Compare(o) <= 0) +} + +// LE checks if v is less than or equal to o. +func (v Version) LE(o Version) bool { + return (v.Compare(o) <= 0) +} + +// Compare compares Versions v to o: +// -1 == v is less than o +// 0 == v is equal to o +// 1 == v is greater than o +func (v Version) Compare(o Version) int { + if v.Major != o.Major { + if v.Major > o.Major { + return 1 + } + return -1 + } + if v.Minor != o.Minor { + if v.Minor > o.Minor { + return 1 + } + return -1 + } + if v.Patch != o.Patch { + if v.Patch > o.Patch { + return 1 + } + return -1 + } + + // Quick comparison if a version has no prerelease versions + if len(v.Pre) == 0 && len(o.Pre) == 0 { + return 0 + } else if len(v.Pre) == 0 && len(o.Pre) > 0 { + return 1 + } else if len(v.Pre) > 0 && len(o.Pre) == 0 { + return -1 + } + + i := 0 + for ; i < len(v.Pre) && i < len(o.Pre); i++ { + if comp := v.Pre[i].Compare(o.Pre[i]); comp == 0 { + continue + } else if comp == 1 { + return 1 + } else { + return -1 + } + } + + // If all pr versions are the equal but one has further prversion, this one greater + if i == len(v.Pre) && i == len(o.Pre) { + return 0 + } else if i == len(v.Pre) && i < len(o.Pre) { + return -1 + } else { + return 1 + } + +} + +// Validate validates v and returns error in case +func (v Version) Validate() error { + // Major, Minor, Patch already validated using uint64 + + for _, pre := range v.Pre { + if !pre.IsNum { //Numeric prerelease versions already uint64 + if len(pre.VersionStr) == 0 { + return fmt.Errorf("Prerelease can not be empty %q", pre.VersionStr) + } + if !containsOnly(pre.VersionStr, alphanum) { + return fmt.Errorf("Invalid character(s) found in prerelease %q", pre.VersionStr) + } + } + } + + for _, build := range v.Build { + if len(build) == 0 { + return fmt.Errorf("Build meta data can not be empty %q", build) + } + if !containsOnly(build, alphanum) { + return fmt.Errorf("Invalid character(s) found in build meta data %q", build) + } + } + + return nil +} + +// New is an alias for Parse and returns a pointer, parses version string and returns a validated Version or error +func New(s string) (vp *Version, err error) { + v, err := Parse(s) + vp = &v + return +} + +// Make is an alias for Parse, parses version string and returns a validated Version or error +func Make(s string) (Version, error) { + return Parse(s) +} + +// ParseTolerant allows for certain version specifications that do not strictly adhere to semver +// specs to be parsed by this library. It does so by normalizing versions before passing them to +// Parse(). It currently trims spaces, removes a "v" prefix, and adds a 0 patch number to versions +// with only major and minor components specified +func ParseTolerant(s string) (Version, error) { + s = strings.TrimSpace(s) + s = strings.TrimPrefix(s, "v") + + // Split into major.minor.(patch+pr+meta) + parts := strings.SplitN(s, ".", 3) + if len(parts) < 3 { + if strings.ContainsAny(parts[len(parts)-1], "+-") { + return Version{}, errors.New("Short version cannot contain PreRelease/Build meta data") + } + for len(parts) < 3 { + parts = append(parts, "0") + } + s = strings.Join(parts, ".") + } + + return Parse(s) +} + +// Parse parses version string and returns a validated Version or error +func Parse(s string) (Version, error) { + if len(s) == 0 { + return Version{}, errors.New("Version string empty") + } + + // Split into major.minor.(patch+pr+meta) + parts := strings.SplitN(s, ".", 3) + if len(parts) != 3 { + return Version{}, errors.New("No Major.Minor.Patch elements found") + } + + // Major + if !containsOnly(parts[0], numbers) { + return Version{}, fmt.Errorf("Invalid character(s) found in major number %q", parts[0]) + } + if hasLeadingZeroes(parts[0]) { + return Version{}, fmt.Errorf("Major number must not contain leading zeroes %q", parts[0]) + } + major, err := strconv.ParseUint(parts[0], 10, 64) + if err != nil { + return Version{}, err + } + + // Minor + if !containsOnly(parts[1], numbers) { + return Version{}, fmt.Errorf("Invalid character(s) found in minor number %q", parts[1]) + } + if hasLeadingZeroes(parts[1]) { + return Version{}, fmt.Errorf("Minor number must not contain leading zeroes %q", parts[1]) + } + minor, err := strconv.ParseUint(parts[1], 10, 64) + if err != nil { + return Version{}, err + } + + v := Version{} + v.Major = major + v.Minor = minor + + var build, prerelease []string + patchStr := parts[2] + + if buildIndex := strings.IndexRune(patchStr, '+'); buildIndex != -1 { + build = strings.Split(patchStr[buildIndex+1:], ".") + patchStr = patchStr[:buildIndex] + } + + if preIndex := strings.IndexRune(patchStr, '-'); preIndex != -1 { + prerelease = strings.Split(patchStr[preIndex+1:], ".") + patchStr = patchStr[:preIndex] + } + + if !containsOnly(patchStr, numbers) { + return Version{}, fmt.Errorf("Invalid character(s) found in patch number %q", patchStr) + } + if hasLeadingZeroes(patchStr) { + return Version{}, fmt.Errorf("Patch number must not contain leading zeroes %q", patchStr) + } + patch, err := strconv.ParseUint(patchStr, 10, 64) + if err != nil { + return Version{}, err + } + + v.Patch = patch + + // Prerelease + for _, prstr := range prerelease { + parsedPR, err := NewPRVersion(prstr) + if err != nil { + return Version{}, err + } + v.Pre = append(v.Pre, parsedPR) + } + + // Build meta data + for _, str := range build { + if len(str) == 0 { + return Version{}, errors.New("Build meta data is empty") + } + if !containsOnly(str, alphanum) { + return Version{}, fmt.Errorf("Invalid character(s) found in build meta data %q", str) + } + v.Build = append(v.Build, str) + } + + return v, nil +} + +// MustParse is like Parse but panics if the version cannot be parsed. +func MustParse(s string) Version { + v, err := Parse(s) + if err != nil { + panic(`semver: Parse(` + s + `): ` + err.Error()) + } + return v +} + +// PRVersion represents a PreRelease Version +type PRVersion struct { + VersionStr string + VersionNum uint64 + IsNum bool +} + +// NewPRVersion creates a new valid prerelease version +func NewPRVersion(s string) (PRVersion, error) { + if len(s) == 0 { + return PRVersion{}, errors.New("Prerelease is empty") + } + v := PRVersion{} + if containsOnly(s, numbers) { + if hasLeadingZeroes(s) { + return PRVersion{}, fmt.Errorf("Numeric PreRelease version must not contain leading zeroes %q", s) + } + num, err := strconv.ParseUint(s, 10, 64) + + // Might never be hit, but just in case + if err != nil { + return PRVersion{}, err + } + v.VersionNum = num + v.IsNum = true + } else if containsOnly(s, alphanum) { + v.VersionStr = s + v.IsNum = false + } else { + return PRVersion{}, fmt.Errorf("Invalid character(s) found in prerelease %q", s) + } + return v, nil +} + +// IsNumeric checks if prerelease-version is numeric +func (v PRVersion) IsNumeric() bool { + return v.IsNum +} + +// Compare compares two PreRelease Versions v and o: +// -1 == v is less than o +// 0 == v is equal to o +// 1 == v is greater than o +func (v PRVersion) Compare(o PRVersion) int { + if v.IsNum && !o.IsNum { + return -1 + } else if !v.IsNum && o.IsNum { + return 1 + } else if v.IsNum && o.IsNum { + if v.VersionNum == o.VersionNum { + return 0 + } else if v.VersionNum > o.VersionNum { + return 1 + } else { + return -1 + } + } else { // both are Alphas + if v.VersionStr == o.VersionStr { + return 0 + } else if v.VersionStr > o.VersionStr { + return 1 + } else { + return -1 + } + } +} + +// PreRelease version to string +func (v PRVersion) String() string { + if v.IsNum { + return strconv.FormatUint(v.VersionNum, 10) + } + return v.VersionStr +} + +func containsOnly(s string, set string) bool { + return strings.IndexFunc(s, func(r rune) bool { + return !strings.ContainsRune(set, r) + }) == -1 +} + +func hasLeadingZeroes(s string) bool { + return len(s) > 1 && s[0] == '0' +} + +// NewBuildVersion creates a new valid build version +func NewBuildVersion(s string) (string, error) { + if len(s) == 0 { + return "", errors.New("Buildversion is empty") + } + if !containsOnly(s, alphanum) { + return "", fmt.Errorf("Invalid character(s) found in build meta data %q", s) + } + return s, nil +} diff --git a/build/manifest/vendor/github.com/blang/semver/sort.go b/build/manifest/vendor/github.com/blang/semver/sort.go new file mode 100644 index 0000000..e18f880 --- /dev/null +++ b/build/manifest/vendor/github.com/blang/semver/sort.go @@ -0,0 +1,28 @@ +package semver + +import ( + "sort" +) + +// Versions represents multiple versions. +type Versions []Version + +// Len returns length of version collection +func (s Versions) Len() int { + return len(s) +} + +// Swap swaps two versions inside the collection by its indices +func (s Versions) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +// Less checks if version at index i is less than version at index j +func (s Versions) Less(i, j int) bool { + return s[i].LT(s[j]) +} + +// Sort sorts a slice of versions +func Sort(versions []Version) { + sort.Sort(Versions(versions)) +} diff --git a/build/manifest/vendor/github.com/blang/semver/sql.go b/build/manifest/vendor/github.com/blang/semver/sql.go new file mode 100644 index 0000000..eb4d802 --- /dev/null +++ b/build/manifest/vendor/github.com/blang/semver/sql.go @@ -0,0 +1,30 @@ +package semver + +import ( + "database/sql/driver" + "fmt" +) + +// Scan implements the database/sql.Scanner interface. +func (v *Version) Scan(src interface{}) (err error) { + var str string + switch src := src.(type) { + case string: + str = src + case []byte: + str = string(src) + default: + return fmt.Errorf("Version.Scan: cannot convert %T to string.", src) + } + + if t, err := Parse(str); err == nil { + *v = t + } + + return +} + +// Value implements the database/sql/driver.Valuer interface. +func (v Version) Value() (driver.Value, error) { + return v.String(), nil +} diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/NOTICE.txt b/build/manifest/vendor/github.com/mattermost/mattermost-server/NOTICE.txt index 5514129..e4b8017 100644 --- a/build/manifest/vendor/github.com/mattermost/mattermost-server/NOTICE.txt +++ b/build/manifest/vendor/github.com/mattermost/mattermost-server/NOTICE.txt @@ -429,6 +429,41 @@ Go package for fast and reliable abstraction of browser user agent strings. --- +## blang/semver + +This product contains 'semver' by Benedikt Lang. + +Semantic Versioning (semver) library written in golang + +* HOMEPAGE: + * https://github.com/blang/semver + +* LICENSE: MIT + +The MIT License + +Copyright (c) 2014 Benedikt Lang + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +--- + ## dgryski/dgoogauth This product contains 'dgoogauth' by Damian Gryski. @@ -2947,6 +2982,41 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --- +## sirupsen/logrus + +This product contains 'logrus' by Simon Eskildsen. + +Structured, pluggable logging for Go. + +* HOMEPAGE: + * https://github.com/sirupsen/logrus + +* LICENSE: MIT + +The MIT License (MIT) + +Copyright (c) 2014 Simon Eskildsen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +--- + ## spf13/cobra This product contains 'cobra' by Steve Francia. diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/channel.go b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/channel.go index 529c49d..f8867ba 100644 --- a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/channel.go +++ b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/channel.go @@ -29,6 +29,9 @@ const ( CHANNEL_HEADER_MAX_RUNES = 1024 CHANNEL_PURPOSE_MAX_RUNES = 250 CHANNEL_CACHE_SIZE = 25000 + + CHANNEL_SORT_BY_USERNAME = "username" + CHANNEL_SORT_BY_STATUS = "status" ) type Channel struct { diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/channel_member.go b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/channel_member.go index 941db62..753e0eb 100644 --- a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/channel_member.go +++ b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/channel_member.go @@ -11,12 +11,16 @@ import ( ) const ( - CHANNEL_NOTIFY_DEFAULT = "default" - CHANNEL_NOTIFY_ALL = "all" - CHANNEL_NOTIFY_MENTION = "mention" - CHANNEL_NOTIFY_NONE = "none" - CHANNEL_MARK_UNREAD_ALL = "all" - CHANNEL_MARK_UNREAD_MENTION = "mention" + CHANNEL_NOTIFY_DEFAULT = "default" + CHANNEL_NOTIFY_ALL = "all" + CHANNEL_NOTIFY_MENTION = "mention" + CHANNEL_NOTIFY_NONE = "none" + CHANNEL_MARK_UNREAD_ALL = "all" + CHANNEL_MARK_UNREAD_MENTION = "mention" + IGNORE_CHANNEL_MENTIONS_DEFAULT = "default" + IGNORE_CHANNEL_MENTIONS_OFF = "off" + IGNORE_CHANNEL_MENTIONS_ON = "on" + IGNORE_CHANNEL_MENTIONS_NOTIFY_PROP = "ignore_channel_mentions" ) type ChannelUnread struct { @@ -116,6 +120,12 @@ func (o *ChannelMember) IsValid() *AppError { } } + if ignoreChannelMentions, ok := o.NotifyProps[IGNORE_CHANNEL_MENTIONS_NOTIFY_PROP]; ok { + if len(ignoreChannelMentions) > 40 || !IsIgnoreChannelMentionsValid(ignoreChannelMentions) { + return NewAppError("ChannelMember.IsValid", "model.channel_member.is_valid.ignore_channel_mentions_value.app_error", nil, "ignore_channel_mentions="+ignoreChannelMentions, http.StatusBadRequest) + } + } + return nil } @@ -146,11 +156,16 @@ func IsSendEmailValid(sendEmail string) bool { return sendEmail == CHANNEL_NOTIFY_DEFAULT || sendEmail == "true" || sendEmail == "false" } +func IsIgnoreChannelMentionsValid(ignoreChannelMentions string) bool { + return ignoreChannelMentions == IGNORE_CHANNEL_MENTIONS_ON || ignoreChannelMentions == IGNORE_CHANNEL_MENTIONS_OFF || ignoreChannelMentions == IGNORE_CHANNEL_MENTIONS_DEFAULT +} + func GetDefaultChannelNotifyProps() StringMap { return StringMap{ - DESKTOP_NOTIFY_PROP: CHANNEL_NOTIFY_DEFAULT, - MARK_UNREAD_NOTIFY_PROP: CHANNEL_MARK_UNREAD_ALL, - PUSH_NOTIFY_PROP: CHANNEL_NOTIFY_DEFAULT, - EMAIL_NOTIFY_PROP: CHANNEL_NOTIFY_DEFAULT, + DESKTOP_NOTIFY_PROP: CHANNEL_NOTIFY_DEFAULT, + MARK_UNREAD_NOTIFY_PROP: CHANNEL_MARK_UNREAD_ALL, + PUSH_NOTIFY_PROP: CHANNEL_NOTIFY_DEFAULT, + EMAIL_NOTIFY_PROP: CHANNEL_NOTIFY_DEFAULT, + IGNORE_CHANNEL_MENTIONS_NOTIFY_PROP: IGNORE_CHANNEL_MENTIONS_DEFAULT, } } diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/client4.go b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/client4.go index 57c4fb7..d064794 100644 --- a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/client4.go +++ b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/client4.go @@ -5,6 +5,7 @@ package model import ( "bytes" + "encoding/json" "fmt" "io" "io/ioutil" @@ -62,15 +63,14 @@ type Client4 struct { func closeBody(r *http.Response) { if r.Body != nil { - ioutil.ReadAll(r.Body) - r.Body.Close() + _, _ = ioutil.ReadAll(r.Body) + _ = r.Body.Close() } } // Must is a convenience function used for testing. func (c *Client4) Must(result interface{}, resp *Response) interface{} { if resp.Error != nil { - time.Sleep(time.Second) panic(resp.Error) } @@ -401,7 +401,7 @@ func (c *Client4) GetRedirectLocationRoute() string { return fmt.Sprintf("/redirect_location") } -func (c *Client4) GetRegisterTermsOfServiceRoute(userId string) string { +func (c *Client4) GetUserTermsOfServiceRoute(userId string) string { return c.GetUserRoute(userId) + "/terms_of_service" } @@ -417,6 +417,10 @@ func (c *Client4) DoApiPost(url string, data string) (*http.Response, *AppError) return c.DoApiRequest(http.MethodPost, c.ApiUrl+url, data, "") } +func (c *Client4) doApiPostBytes(url string, data []byte) (*http.Response, *AppError) { + return c.doApiRequestBytes(http.MethodPost, c.ApiUrl+url, data, "") +} + func (c *Client4) DoApiPut(url string, data string) (*http.Response, *AppError) { return c.DoApiRequest(http.MethodPut, c.ApiUrl+url, data, "") } @@ -426,7 +430,15 @@ func (c *Client4) DoApiDelete(url string) (*http.Response, *AppError) { } func (c *Client4) DoApiRequest(method, url, data, etag string) (*http.Response, *AppError) { - rq, _ := http.NewRequest(method, url, strings.NewReader(data)) + return c.doApiRequestReader(method, url, strings.NewReader(data), etag) +} + +func (c *Client4) doApiRequestBytes(method, url string, data []byte, etag string) (*http.Response, *AppError) { + return c.doApiRequestReader(method, url, bytes.NewReader(data), etag) +} + +func (c *Client4) doApiRequestReader(method, url string, data io.Reader, etag string) (*http.Response, *AppError) { + rq, _ := http.NewRequest(method, url, data) if len(etag) > 0 { rq.Header.Set(HEADER_ETAG_CLIENT, etag) @@ -437,22 +449,26 @@ func (c *Client4) DoApiRequest(method, url, data, etag string) (*http.Response, } if c.HttpHeader != nil && len(c.HttpHeader) > 0 { - for k, v := range c.HttpHeader { rq.Header.Set(k, v) } } - if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil { + rp, err := c.HttpClient.Do(rq) + if err != nil || rp == nil { return nil, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0) - } else if rp.StatusCode == 304 { - return rp, nil - } else if rp.StatusCode >= 300 { - defer closeBody(rp) - return rp, AppErrorFromJson(rp.Body) - } else { + } + + if rp.StatusCode == 304 { return rp, nil } + + if rp.StatusCode >= 300 { + defer closeBody(rp) + return rp, AppErrorFromJson(rp.Body) + } + + return rp, nil } func (c *Client4) DoUploadFile(url string, data []byte, contentType string) (*FileUploadResponse, *Response) { @@ -463,17 +479,17 @@ func (c *Client4) DoUploadFile(url string, data []byte, contentType string) (*Fi rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } - if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil { + rp, err := c.HttpClient.Do(rq) + if err != nil || rp == nil { return nil, BuildErrorResponse(rp, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)) - } else { - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } else { - return FileUploadResponseFromJson(rp.Body), BuildResponse(rp) - } } + defer closeBody(rp) + + if rp.StatusCode >= 300 { + return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) + } + + return FileUploadResponseFromJson(rp.Body), BuildResponse(rp) } func (c *Client4) DoEmojiUploadFile(url string, data []byte, contentType string) (*Emoji, *Response) { @@ -484,17 +500,17 @@ func (c *Client4) DoEmojiUploadFile(url string, data []byte, contentType string) rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } - if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil { + rp, err := c.HttpClient.Do(rq) + if err != nil || rp == nil { return nil, BuildErrorResponse(rp, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)) - } else { - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } else { - return EmojiFromJson(rp.Body), BuildResponse(rp) - } } + defer closeBody(rp) + + if rp.StatusCode >= 300 { + return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) + } + + return EmojiFromJson(rp.Body), BuildResponse(rp) } func (c *Client4) DoUploadImportTeam(url string, data []byte, contentType string) (map[string]string, *Response) { @@ -505,17 +521,17 @@ func (c *Client4) DoUploadImportTeam(url string, data []byte, contentType string rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } - if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil { + rp, err := c.HttpClient.Do(rq) + if err != nil || rp == nil { return nil, BuildErrorResponse(rp, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)) - } else { - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } else { - return MapFromJson(rp.Body), BuildResponse(rp) - } } + defer closeBody(rp) + + if rp.StatusCode >= 300 { + return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) + } + + return MapFromJson(rp.Body), BuildResponse(rp) } // CheckStatusOK is a convenience function for checking the standard OK response @@ -571,330 +587,345 @@ func (c *Client4) LoginWithDevice(loginId string, password string, deviceId stri } func (c *Client4) login(m map[string]string) (*User, *Response) { - if r, err := c.DoApiPost("/users/login", MapToJson(m)); err != nil { + r, err := c.DoApiPost("/users/login", MapToJson(m)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - c.AuthToken = r.Header.Get(HEADER_TOKEN) - c.AuthType = HEADER_BEARER - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + c.AuthToken = r.Header.Get(HEADER_TOKEN) + c.AuthType = HEADER_BEARER + return UserFromJson(r.Body), BuildResponse(r) } // Logout terminates the current user's session. func (c *Client4) Logout() (bool, *Response) { - if r, err := c.DoApiPost("/users/logout", ""); err != nil { + r, err := c.DoApiPost("/users/logout", "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - c.AuthToken = "" - c.AuthType = HEADER_BEARER - - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + c.AuthToken = "" + c.AuthType = HEADER_BEARER + return CheckStatusOK(r), BuildResponse(r) } // SwitchAccountType changes a user's login type from one type to another. func (c *Client4) SwitchAccountType(switchRequest *SwitchRequest) (string, *Response) { - if r, err := c.DoApiPost(c.GetUsersRoute()+"/login/switch", switchRequest.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetUsersRoute()+"/login/switch", switchRequest.ToJson()) + if err != nil { return "", BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return MapFromJson(r.Body)["follow_link"], BuildResponse(r) } + defer closeBody(r) + return MapFromJson(r.Body)["follow_link"], BuildResponse(r) } // User Section // CreateUser creates a user in the system based on the provided user struct. func (c *Client4) CreateUser(user *User) (*User, *Response) { - if r, err := c.DoApiPost(c.GetUsersRoute(), user.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetUsersRoute(), user.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserFromJson(r.Body), BuildResponse(r) } // CreateUserWithToken creates a user in the system based on the provided tokenId. func (c *Client4) CreateUserWithToken(user *User, tokenId string) (*User, *Response) { - var query string - if tokenId != "" { - query = fmt.Sprintf("?t=%v", tokenId) - } else { + if tokenId == "" { err := NewAppError("MissingHashOrData", "api.user.create_user.missing_token.app_error", nil, "", http.StatusBadRequest) return nil, &Response{StatusCode: err.StatusCode, Error: err} } - if r, err := c.DoApiPost(c.GetUsersRoute()+query, user.ToJson()); err != nil { + + query := fmt.Sprintf("?t=%v", tokenId) + r, err := c.DoApiPost(c.GetUsersRoute()+query, user.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + + return UserFromJson(r.Body), BuildResponse(r) } // CreateUserWithInviteId creates a user in the system based on the provided invited id. func (c *Client4) CreateUserWithInviteId(user *User, inviteId string) (*User, *Response) { - var query string - if inviteId != "" { - query = fmt.Sprintf("?iid=%v", url.QueryEscape(inviteId)) - } else { + if inviteId == "" { err := NewAppError("MissingInviteId", "api.user.create_user.missing_invite_id.app_error", nil, "", http.StatusBadRequest) return nil, &Response{StatusCode: err.StatusCode, Error: err} } - if r, err := c.DoApiPost(c.GetUsersRoute()+query, user.ToJson()); err != nil { + + query := fmt.Sprintf("?iid=%v", url.QueryEscape(inviteId)) + r, err := c.DoApiPost(c.GetUsersRoute()+query, user.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + + return UserFromJson(r.Body), BuildResponse(r) } // GetMe returns the logged in user. func (c *Client4) GetMe(etag string) (*User, *Response) { - if r, err := c.DoApiGet(c.GetUserRoute(ME), etag); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(ME), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserFromJson(r.Body), BuildResponse(r) } // GetUser returns a user based on the provided user id string. func (c *Client4) GetUser(userId, etag string) (*User, *Response) { - if r, err := c.DoApiGet(c.GetUserRoute(userId), etag); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserFromJson(r.Body), BuildResponse(r) } // GetUserByUsername returns a user based on the provided user name string. func (c *Client4) GetUserByUsername(userName, etag string) (*User, *Response) { - if r, err := c.DoApiGet(c.GetUserByUsernameRoute(userName), etag); err != nil { + r, err := c.DoApiGet(c.GetUserByUsernameRoute(userName), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserFromJson(r.Body), BuildResponse(r) } // GetUserByEmail returns a user based on the provided user email string. func (c *Client4) GetUserByEmail(email, etag string) (*User, *Response) { - if r, err := c.DoApiGet(c.GetUserByEmailRoute(email), etag); err != nil { + r, err := c.DoApiGet(c.GetUserByEmailRoute(email), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserFromJson(r.Body), BuildResponse(r) } // AutocompleteUsersInTeam returns the users on a team based on search term. -func (c *Client4) AutocompleteUsersInTeam(teamId string, username string, etag string) (*UserAutocomplete, *Response) { - query := fmt.Sprintf("?in_team=%v&name=%v", teamId, username) - if r, err := c.DoApiGet(c.GetUsersRoute()+"/autocomplete"+query, etag); err != nil { +func (c *Client4) AutocompleteUsersInTeam(teamId string, username string, limit int, etag string) (*UserAutocomplete, *Response) { + query := fmt.Sprintf("?in_team=%v&name=%v&limit=%d", teamId, username, limit) + r, err := c.DoApiGet(c.GetUsersRoute()+"/autocomplete"+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserAutocompleteFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserAutocompleteFromJson(r.Body), BuildResponse(r) } // AutocompleteUsersInChannel returns the users in a channel based on search term. -func (c *Client4) AutocompleteUsersInChannel(teamId string, channelId string, username string, etag string) (*UserAutocomplete, *Response) { - query := fmt.Sprintf("?in_team=%v&in_channel=%v&name=%v", teamId, channelId, username) - if r, err := c.DoApiGet(c.GetUsersRoute()+"/autocomplete"+query, etag); err != nil { +func (c *Client4) AutocompleteUsersInChannel(teamId string, channelId string, username string, limit int, etag string) (*UserAutocomplete, *Response) { + query := fmt.Sprintf("?in_team=%v&in_channel=%v&name=%v&limit=%d", teamId, channelId, username, limit) + r, err := c.DoApiGet(c.GetUsersRoute()+"/autocomplete"+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserAutocompleteFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserAutocompleteFromJson(r.Body), BuildResponse(r) } // AutocompleteUsers returns the users in the system based on search term. -func (c *Client4) AutocompleteUsers(username string, etag string) (*UserAutocomplete, *Response) { - query := fmt.Sprintf("?name=%v", username) - if r, err := c.DoApiGet(c.GetUsersRoute()+"/autocomplete"+query, etag); err != nil { +func (c *Client4) AutocompleteUsers(username string, limit int, etag string) (*UserAutocomplete, *Response) { + query := fmt.Sprintf("?name=%v&limit=%d", username, limit) + r, err := c.DoApiGet(c.GetUsersRoute()+"/autocomplete"+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserAutocompleteFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserAutocompleteFromJson(r.Body), BuildResponse(r) } -// GetProfileImage gets user's profile image. Must be logged in or be a system administrator. -func (c *Client4) GetProfileImage(userId, etag string) ([]byte, *Response) { - if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/image", etag); err != nil { - return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - - if data, err := ioutil.ReadAll(r.Body); err != nil { - return nil, BuildErrorResponse(r, NewAppError("GetProfileImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } else { - return data, BuildResponse(r) - } +// GetDefaultProfileImage gets the default user's profile image. Must be logged in. +func (c *Client4) GetDefaultProfileImage(userId string) ([]byte, *Response) { + r, appErr := c.DoApiGet(c.GetUserRoute(userId)+"/image/default", "") + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) } + defer closeBody(r) + + data, err := ioutil.ReadAll(r.Body) + if err != nil { + return nil, BuildErrorResponse(r, NewAppError("GetDefaultProfileImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) + } + + return data, BuildResponse(r) +} + +// GetProfileImage gets user's profile image. Must be logged in. +func (c *Client4) GetProfileImage(userId, etag string) ([]byte, *Response) { + r, appErr := c.DoApiGet(c.GetUserRoute(userId)+"/image", etag) + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) + } + defer closeBody(r) + + data, err := ioutil.ReadAll(r.Body) + if err != nil { + return nil, BuildErrorResponse(r, NewAppError("GetProfileImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) + } + return data, BuildResponse(r) } // GetUsers returns a page of users on the system. Page counting starts at 0. func (c *Client4) GetUsers(page int, perPage int, etag string) ([]*User, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserListFromJson(r.Body), BuildResponse(r) } // GetUsersInTeam returns a page of users on a team. Page counting starts at 0. func (c *Client4) GetUsersInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) { query := fmt.Sprintf("?in_team=%v&page=%v&per_page=%v", teamId, page, perPage) - if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserListFromJson(r.Body), BuildResponse(r) } // GetNewUsersInTeam returns a page of users on a team. Page counting starts at 0. func (c *Client4) GetNewUsersInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) { query := fmt.Sprintf("?sort=create_at&in_team=%v&page=%v&per_page=%v", teamId, page, perPage) - if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserListFromJson(r.Body), BuildResponse(r) } // GetRecentlyActiveUsersInTeam returns a page of users on a team. Page counting starts at 0. func (c *Client4) GetRecentlyActiveUsersInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) { query := fmt.Sprintf("?sort=last_activity_at&in_team=%v&page=%v&per_page=%v", teamId, page, perPage) - if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserListFromJson(r.Body), BuildResponse(r) } // GetUsersNotInTeam returns a page of users who are not in a team. Page counting starts at 0. func (c *Client4) GetUsersNotInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) { query := fmt.Sprintf("?not_in_team=%v&page=%v&per_page=%v", teamId, page, perPage) - if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserListFromJson(r.Body), BuildResponse(r) } // GetUsersInChannel returns a page of users in a channel. Page counting starts at 0. func (c *Client4) GetUsersInChannel(channelId string, page int, perPage int, etag string) ([]*User, *Response) { query := fmt.Sprintf("?in_channel=%v&page=%v&per_page=%v", channelId, page, perPage) - if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserListFromJson(r.Body), BuildResponse(r) } -// GetUsersInChannelStatus returns a page of users in a channel. Page counting starts at 0. Sorted by Status +// GetUsersInChannelByStatus returns a page of users in a channel. Page counting starts at 0. Sorted by Status func (c *Client4) GetUsersInChannelByStatus(channelId string, page int, perPage int, etag string) ([]*User, *Response) { query := fmt.Sprintf("?in_channel=%v&page=%v&per_page=%v&sort=status", channelId, page, perPage) - if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserListFromJson(r.Body), BuildResponse(r) } // GetUsersNotInChannel returns a page of users not in a channel. Page counting starts at 0. func (c *Client4) GetUsersNotInChannel(teamId, channelId string, page int, perPage int, etag string) ([]*User, *Response) { query := fmt.Sprintf("?in_team=%v¬_in_channel=%v&page=%v&per_page=%v", teamId, channelId, page, perPage) - if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserListFromJson(r.Body), BuildResponse(r) } // GetUsersWithoutTeam returns a page of users on the system that aren't on any teams. Page counting starts at 0. func (c *Client4) GetUsersWithoutTeam(page int, perPage int, etag string) ([]*User, *Response) { query := fmt.Sprintf("?without_team=1&page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserListFromJson(r.Body), BuildResponse(r) } // GetUsersByIds returns a list of users based on the provided user ids. func (c *Client4) GetUsersByIds(userIds []string) ([]*User, *Response) { - if r, err := c.DoApiPost(c.GetUsersRoute()+"/ids", ArrayToJson(userIds)); err != nil { + r, err := c.DoApiPost(c.GetUsersRoute()+"/ids", ArrayToJson(userIds)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserListFromJson(r.Body), BuildResponse(r) } // GetUsersByUsernames returns a list of users based on the provided usernames. func (c *Client4) GetUsersByUsernames(usernames []string) ([]*User, *Response) { - if r, err := c.DoApiPost(c.GetUsersRoute()+"/usernames", ArrayToJson(usernames)); err != nil { + r, err := c.DoApiPost(c.GetUsersRoute()+"/usernames", ArrayToJson(usernames)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserListFromJson(r.Body), BuildResponse(r) } // SearchUsers returns a list of users based on some search criteria. func (c *Client4) SearchUsers(search *UserSearch) ([]*User, *Response) { - if r, err := c.DoApiPost(c.GetUsersRoute()+"/search", search.ToJson()); err != nil { + r, err := c.doApiPostBytes(c.GetUsersRoute()+"/search", search.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserListFromJson(r.Body), BuildResponse(r) } // UpdateUser updates a user in the system based on the provided user struct. func (c *Client4) UpdateUser(user *User) (*User, *Response) { - if r, err := c.DoApiPut(c.GetUserRoute(user.Id), user.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetUserRoute(user.Id), user.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserFromJson(r.Body), BuildResponse(r) } // PatchUser partially updates a user in the system. Any missing fields are not updated. func (c *Client4) PatchUser(userId string, patch *UserPatch) (*User, *Response) { - if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/patch", patch.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetUserRoute(userId)+"/patch", patch.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserFromJson(r.Body), BuildResponse(r) } // UpdateUserAuth updates a user AuthData (uthData, authService and password) in the system. func (c *Client4) UpdateUserAuth(userId string, userAuth *UserAuth) (*UserAuth, *Response) { - if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/auth", userAuth.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetUserRoute(userId)+"/auth", userAuth.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserAuthFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserAuthFromJson(r.Body), BuildResponse(r) } // UpdateUserMfa activates multi-factor authentication for a user if activate @@ -905,12 +936,12 @@ func (c *Client4) UpdateUserMfa(userId, code string, activate bool) (bool, *Resp requestBody["activate"] = activate requestBody["code"] = code - if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/mfa", StringInterfaceToJson(requestBody)); err != nil { + r, err := c.DoApiPut(c.GetUserRoute(userId)+"/mfa", StringInterfaceToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // CheckUserMfa checks whether a user has MFA active on their account or not based on the @@ -918,178 +949,178 @@ func (c *Client4) UpdateUserMfa(userId, code string, activate bool) (bool, *Resp func (c *Client4) CheckUserMfa(loginId string) (bool, *Response) { requestBody := make(map[string]interface{}) requestBody["login_id"] = loginId - - if r, err := c.DoApiPost(c.GetUsersRoute()+"/mfa", StringInterfaceToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetUsersRoute()+"/mfa", StringInterfaceToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - data := StringInterfaceFromJson(r.Body) - if mfaRequired, ok := data["mfa_required"].(bool); !ok { - return false, BuildResponse(r) - } else { - return mfaRequired, BuildResponse(r) - } } + defer closeBody(r) + + data := StringInterfaceFromJson(r.Body) + mfaRequired, ok := data["mfa_required"].(bool) + if !ok { + return false, BuildResponse(r) + } + return mfaRequired, BuildResponse(r) } // GenerateMfaSecret will generate a new MFA secret for a user and return it as a string and // as a base64 encoded image QR code. func (c *Client4) GenerateMfaSecret(userId string) (*MfaSecret, *Response) { - if r, err := c.DoApiPost(c.GetUserRoute(userId)+"/mfa/generate", ""); err != nil { + r, err := c.DoApiPost(c.GetUserRoute(userId)+"/mfa/generate", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return MfaSecretFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return MfaSecretFromJson(r.Body), BuildResponse(r) } // UpdateUserPassword updates a user's password. Must be logged in as the user or be a system administrator. func (c *Client4) UpdateUserPassword(userId, currentPassword, newPassword string) (bool, *Response) { requestBody := map[string]string{"current_password": currentPassword, "new_password": newPassword} - if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/password", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPut(c.GetUserRoute(userId)+"/password", MapToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // UpdateUserRoles updates a user's roles in the system. A user can have "system_user" and "system_admin" roles. func (c *Client4) UpdateUserRoles(userId, roles string) (bool, *Response) { requestBody := map[string]string{"roles": roles} - if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/roles", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPut(c.GetUserRoute(userId)+"/roles", MapToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // UpdateUserActive updates status of a user whether active or not. func (c *Client4) UpdateUserActive(userId string, active bool) (bool, *Response) { requestBody := make(map[string]interface{}) requestBody["active"] = active - - if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/active", StringInterfaceToJson(requestBody)); err != nil { + r, err := c.DoApiPut(c.GetUserRoute(userId)+"/active", StringInterfaceToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + + return CheckStatusOK(r), BuildResponse(r) } // DeleteUser deactivates a user in the system based on the provided user id string. func (c *Client4) DeleteUser(userId string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetUserRoute(userId)); err != nil { + r, err := c.DoApiDelete(c.GetUserRoute(userId)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // SendPasswordResetEmail will send a link for password resetting to a user with the // provided email. func (c *Client4) SendPasswordResetEmail(email string) (bool, *Response) { requestBody := map[string]string{"email": email} - if r, err := c.DoApiPost(c.GetUsersRoute()+"/password/reset/send", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetUsersRoute()+"/password/reset/send", MapToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // ResetPassword uses a recovery code to update reset a user's password. func (c *Client4) ResetPassword(token, newPassword string) (bool, *Response) { requestBody := map[string]string{"token": token, "new_password": newPassword} - if r, err := c.DoApiPost(c.GetUsersRoute()+"/password/reset", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetUsersRoute()+"/password/reset", MapToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetSessions returns a list of sessions based on the provided user id string. func (c *Client4) GetSessions(userId, etag string) ([]*Session, *Response) { - if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/sessions", etag); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId)+"/sessions", etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return SessionsFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return SessionsFromJson(r.Body), BuildResponse(r) } // RevokeSession revokes a user session based on the provided user id and session id strings. func (c *Client4) RevokeSession(userId, sessionId string) (bool, *Response) { requestBody := map[string]string{"session_id": sessionId} - if r, err := c.DoApiPost(c.GetUserRoute(userId)+"/sessions/revoke", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetUserRoute(userId)+"/sessions/revoke", MapToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // RevokeAllSessions revokes all sessions for the provided user id string. func (c *Client4) RevokeAllSessions(userId string) (bool, *Response) { - if r, err := c.DoApiPost(c.GetUserRoute(userId)+"/sessions/revoke/all", ""); err != nil { + r, err := c.DoApiPost(c.GetUserRoute(userId)+"/sessions/revoke/all", "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // AttachDeviceId attaches a mobile device ID to the current session. func (c *Client4) AttachDeviceId(deviceId string) (bool, *Response) { requestBody := map[string]string{"device_id": deviceId} - if r, err := c.DoApiPut(c.GetUsersRoute()+"/sessions/device", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPut(c.GetUsersRoute()+"/sessions/device", MapToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetTeamsUnreadForUser will return an array with TeamUnread objects that contain the amount // of unread messages and mentions the current user has for the teams it belongs to. // An optional team ID can be set to exclude that team from the results. Must be authenticated. func (c *Client4) GetTeamsUnreadForUser(userId, teamIdToExclude string) ([]*TeamUnread, *Response) { - optional := "" + var optional string if teamIdToExclude != "" { optional += fmt.Sprintf("?exclude_team=%s", url.QueryEscape(teamIdToExclude)) } - if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams/unread"+optional, ""); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams/unread"+optional, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamsUnreadFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamsUnreadFromJson(r.Body), BuildResponse(r) } // GetUserAudits returns a list of audit based on the provided user id string. func (c *Client4) GetUserAudits(userId string, page int, perPage int, etag string) (Audits, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/audits"+query, etag); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId)+"/audits"+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return AuditsFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return AuditsFromJson(r.Body), BuildResponse(r) } // VerifyUserEmail will verify a user's email using the supplied token. func (c *Client4) VerifyUserEmail(token string) (bool, *Response) { requestBody := map[string]string{"token": token} - if r, err := c.DoApiPost(c.GetUsersRoute()+"/email/verify", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetUsersRoute()+"/email/verify", MapToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // SendVerificationEmail will send an email to the user with the provided email address, if @@ -1097,26 +1128,38 @@ func (c *Client4) VerifyUserEmail(token string) (bool, *Response) { // email address. func (c *Client4) SendVerificationEmail(email string) (bool, *Response) { requestBody := map[string]string{"email": email} - if r, err := c.DoApiPost(c.GetUsersRoute()+"/email/verify/send", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetUsersRoute()+"/email/verify/send", MapToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } -// SetProfileImage sets profile image of the user +// SetDefaultProfileImage resets the profile image to a default generated one. +func (c *Client4) SetDefaultProfileImage(userId string) (bool, *Response) { + r, err := c.DoApiDelete(c.GetUserRoute(userId) + "/image") + if err != nil { + return false, BuildErrorResponse(r, err) + } + return CheckStatusOK(r), BuildResponse(r) +} + +// SetProfileImage sets profile image of the user. func (c *Client4) SetProfileImage(userId string, data []byte) (bool, *Response) { body := &bytes.Buffer{} writer := multipart.NewWriter(body) - if part, err := writer.CreateFormFile("image", "profile.png"); err != nil { - return false, &Response{Error: NewAppError("SetProfileImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} - } else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { + part, err := writer.CreateFormFile("image", "profile.png") + if err != nil { return false, &Response{Error: NewAppError("SetProfileImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} } - if err := writer.Close(); err != nil { + if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { + return false, &Response{Error: NewAppError("SetProfileImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} + } + + if err = writer.Close(); err != nil { return false, &Response{Error: NewAppError("SetProfileImage", "model.client.set_profile_user.writer.app_error", nil, err.Error(), http.StatusBadRequest)} } @@ -1127,18 +1170,18 @@ func (c *Client4) SetProfileImage(userId string, data []byte) (bool, *Response) rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } - if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil { + rp, err := c.HttpClient.Do(rq) + if err != nil || rp == nil { // set to http.StatusForbidden(403) return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetUserRoute(userId)+"/image", "model.client.connecting.app_error", nil, err.Error(), 403)} - } else { - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } else { - return CheckStatusOK(rp), BuildResponse(rp) - } } + defer closeBody(rp) + + if rp.StatusCode >= 300 { + return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) + } + + return CheckStatusOK(rp), BuildResponse(rp) } // CreateUserAccessToken will generate a user access token that can be used in place @@ -1147,12 +1190,12 @@ func (c *Client4) SetProfileImage(userId string, data []byte) (bool, *Response) // permission. A non-blank description is required. func (c *Client4) CreateUserAccessToken(userId, description string) (*UserAccessToken, *Response) { requestBody := map[string]string{"description": description} - if r, err := c.DoApiPost(c.GetUserRoute(userId)+"/tokens", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetUserRoute(userId)+"/tokens", MapToJson(requestBody)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserAccessTokenFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserAccessTokenFromJson(r.Body), BuildResponse(r) } // GetUserAccessTokens will get a page of access tokens' id, description, is_active @@ -1160,12 +1203,12 @@ func (c *Client4) CreateUserAccessToken(userId, description string) (*UserAccess // the 'manage_system' permission. func (c *Client4) GetUserAccessTokens(page int, perPage int) ([]*UserAccessToken, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetUserAccessTokensRoute()+query, ""); err != nil { + r, err := c.DoApiGet(c.GetUserAccessTokensRoute()+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserAccessTokenListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserAccessTokenListFromJson(r.Body), BuildResponse(r) } // GetUserAccessToken will get a user access tokens' id, description, is_active @@ -1173,12 +1216,12 @@ func (c *Client4) GetUserAccessTokens(page int, perPage int) ([]*UserAccessToken // Must have the 'read_user_access_token' permission and if getting for another // user, must have the 'edit_other_users' permission. func (c *Client4) GetUserAccessToken(tokenId string) (*UserAccessToken, *Response) { - if r, err := c.DoApiGet(c.GetUserAccessTokenRoute(tokenId), ""); err != nil { + r, err := c.DoApiGet(c.GetUserAccessTokenRoute(tokenId), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserAccessTokenFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserAccessTokenFromJson(r.Body), BuildResponse(r) } // GetUserAccessTokensForUser will get a paged list of user access tokens showing id, @@ -1187,12 +1230,12 @@ func (c *Client4) GetUserAccessToken(tokenId string) (*UserAccessToken, *Respons // 'edit_other_users' permission. func (c *Client4) GetUserAccessTokensForUser(userId string, page, perPage int) ([]*UserAccessToken, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/tokens"+query, ""); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId)+"/tokens"+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserAccessTokenListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserAccessTokenListFromJson(r.Body), BuildResponse(r) } // RevokeUserAccessToken will revoke a user access token by id. Must have the @@ -1200,22 +1243,22 @@ func (c *Client4) GetUserAccessTokensForUser(userId string, page, perPage int) ( // 'edit_other_users' permission. func (c *Client4) RevokeUserAccessToken(tokenId string) (bool, *Response) { requestBody := map[string]string{"token_id": tokenId} - if r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/revoke", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/revoke", MapToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // SearchUserAccessTokens returns user access tokens matching the provided search term. func (c *Client4) SearchUserAccessTokens(search *UserAccessTokenSearch) ([]*UserAccessToken, *Response) { - if r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/search", search.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/search", search.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserAccessTokenListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserAccessTokenListFromJson(r.Body), BuildResponse(r) } // DisableUserAccessToken will disable a user access token by id. Must have the @@ -1223,12 +1266,12 @@ func (c *Client4) SearchUserAccessTokens(search *UserAccessTokenSearch) ([]*User // 'edit_other_users' permission. func (c *Client4) DisableUserAccessToken(tokenId string) (bool, *Response) { requestBody := map[string]string{"token_id": tokenId} - if r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/disable", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/disable", MapToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // EnableUserAccessToken will enable a user access token by id. Must have the @@ -1236,202 +1279,201 @@ func (c *Client4) DisableUserAccessToken(tokenId string) (bool, *Response) { // 'edit_other_users' permission. func (c *Client4) EnableUserAccessToken(tokenId string) (bool, *Response) { requestBody := map[string]string{"token_id": tokenId} - if r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/enable", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/enable", MapToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // Team Section // CreateTeam creates a team in the system based on the provided team struct. func (c *Client4) CreateTeam(team *Team) (*Team, *Response) { - if r, err := c.DoApiPost(c.GetTeamsRoute(), team.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetTeamsRoute(), team.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamFromJson(r.Body), BuildResponse(r) } // GetTeam returns a team based on the provided team id string. func (c *Client4) GetTeam(teamId, etag string) (*Team, *Response) { - if r, err := c.DoApiGet(c.GetTeamRoute(teamId), etag); err != nil { + r, err := c.DoApiGet(c.GetTeamRoute(teamId), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamFromJson(r.Body), BuildResponse(r) } // GetAllTeams returns all teams based on permissions. func (c *Client4) GetAllTeams(etag string, page int, perPage int) ([]*Team, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetTeamsRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetTeamsRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamListFromJson(r.Body), BuildResponse(r) } // GetTeamByName returns a team based on the provided team name string. func (c *Client4) GetTeamByName(name, etag string) (*Team, *Response) { - if r, err := c.DoApiGet(c.GetTeamByNameRoute(name), etag); err != nil { + r, err := c.DoApiGet(c.GetTeamByNameRoute(name), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamFromJson(r.Body), BuildResponse(r) } // SearchTeams returns teams matching the provided search term. func (c *Client4) SearchTeams(search *TeamSearch) ([]*Team, *Response) { - if r, err := c.DoApiPost(c.GetTeamsRoute()+"/search", search.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetTeamsRoute()+"/search", search.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamListFromJson(r.Body), BuildResponse(r) } // TeamExists returns true or false if the team exist or not. func (c *Client4) TeamExists(name, etag string) (bool, *Response) { - if r, err := c.DoApiGet(c.GetTeamByNameRoute(name)+"/exists", etag); err != nil { + r, err := c.DoApiGet(c.GetTeamByNameRoute(name)+"/exists", etag) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return MapBoolFromJson(r.Body)["exists"], BuildResponse(r) } + defer closeBody(r) + return MapBoolFromJson(r.Body)["exists"], BuildResponse(r) } // GetTeamsForUser returns a list of teams a user is on. Must be logged in as the user // or be a system administrator. func (c *Client4) GetTeamsForUser(userId, etag string) ([]*Team, *Response) { - if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams", etag); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams", etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamListFromJson(r.Body), BuildResponse(r) } // GetTeamMember returns a team member based on the provided team and user id strings. func (c *Client4) GetTeamMember(teamId, userId, etag string) (*TeamMember, *Response) { - if r, err := c.DoApiGet(c.GetTeamMemberRoute(teamId, userId), etag); err != nil { + r, err := c.DoApiGet(c.GetTeamMemberRoute(teamId, userId), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamMemberFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamMemberFromJson(r.Body), BuildResponse(r) } // UpdateTeamMemberRoles will update the roles on a team for a user. func (c *Client4) UpdateTeamMemberRoles(teamId, userId, newRoles string) (bool, *Response) { requestBody := map[string]string{"roles": newRoles} - if r, err := c.DoApiPut(c.GetTeamMemberRoute(teamId, userId)+"/roles", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPut(c.GetTeamMemberRoute(teamId, userId)+"/roles", MapToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // UpdateTeamMemberSchemeRoles will update the scheme-derived roles on a team for a user. func (c *Client4) UpdateTeamMemberSchemeRoles(teamId string, userId string, schemeRoles *SchemeRoles) (bool, *Response) { - if r, err := c.DoApiPut(c.GetTeamMemberRoute(teamId, userId)+"/schemeRoles", schemeRoles.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetTeamMemberRoute(teamId, userId)+"/schemeRoles", schemeRoles.ToJson()) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // UpdateTeam will update a team. func (c *Client4) UpdateTeam(team *Team) (*Team, *Response) { - if r, err := c.DoApiPut(c.GetTeamRoute(team.Id), team.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetTeamRoute(team.Id), team.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamFromJson(r.Body), BuildResponse(r) } // PatchTeam partially updates a team. Any missing fields are not updated. func (c *Client4) PatchTeam(teamId string, patch *TeamPatch) (*Team, *Response) { - if r, err := c.DoApiPut(c.GetTeamRoute(teamId)+"/patch", patch.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetTeamRoute(teamId)+"/patch", patch.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamFromJson(r.Body), BuildResponse(r) } // SoftDeleteTeam deletes the team softly (archive only, not permanent delete). func (c *Client4) SoftDeleteTeam(teamId string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetTeamRoute(teamId)); err != nil { + r, err := c.DoApiDelete(c.GetTeamRoute(teamId)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // PermanentDeleteTeam deletes the team, should only be used when needed for -// compliance and the like +// compliance and the like. func (c *Client4) PermanentDeleteTeam(teamId string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetTeamRoute(teamId) + "?permanent=true"); err != nil { + r, err := c.DoApiDelete(c.GetTeamRoute(teamId) + "?permanent=true") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetTeamMembers returns team members based on the provided team id string. func (c *Client4) GetTeamMembers(teamId string, page int, perPage int, etag string) ([]*TeamMember, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetTeamMembersRoute(teamId)+query, etag); err != nil { + r, err := c.DoApiGet(c.GetTeamMembersRoute(teamId)+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamMembersFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamMembersFromJson(r.Body), BuildResponse(r) } // GetTeamMembersForUser returns the team members for a user. func (c *Client4) GetTeamMembersForUser(userId string, etag string) ([]*TeamMember, *Response) { - if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams/members", etag); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams/members", etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamMembersFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamMembersFromJson(r.Body), BuildResponse(r) } // GetTeamMembersByIds will return an array of team members based on the // team id and a list of user ids provided. Must be authenticated. func (c *Client4) GetTeamMembersByIds(teamId string, userIds []string) ([]*TeamMember, *Response) { - if r, err := c.DoApiPost(fmt.Sprintf("/teams/%v/members/ids", teamId), ArrayToJson(userIds)); err != nil { + r, err := c.DoApiPost(fmt.Sprintf("/teams/%v/members/ids", teamId), ArrayToJson(userIds)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamMembersFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamMembersFromJson(r.Body), BuildResponse(r) } // AddTeamMember adds user to a team and return a team member. func (c *Client4) AddTeamMember(teamId, userId string) (*TeamMember, *Response) { member := &TeamMember{TeamId: teamId, UserId: userId} - - if r, err := c.DoApiPost(c.GetTeamMembersRoute(teamId), member.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetTeamMembersRoute(teamId), member.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamMemberFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamMemberFromJson(r.Body), BuildResponse(r) } // AddTeamMemberFromInvite adds a user to a team and return a team member using an invite id @@ -1447,12 +1489,12 @@ func (c *Client4) AddTeamMemberFromInvite(token, inviteId string) (*TeamMember, query += fmt.Sprintf("?token=%v", token) } - if r, err := c.DoApiPost(c.GetTeamsRoute()+"/members/invite"+query, ""); err != nil { + r, err := c.DoApiPost(c.GetTeamsRoute()+"/members/invite"+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamMemberFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamMemberFromJson(r.Body), BuildResponse(r) } // AddTeamMembers adds a number of users to a team and returns the team members. @@ -1463,56 +1505,56 @@ func (c *Client4) AddTeamMembers(teamId string, userIds []string) ([]*TeamMember members = append(members, member) } - if r, err := c.DoApiPost(c.GetTeamMembersRoute(teamId)+"/batch", TeamMembersToJson(members)); err != nil { + r, err := c.DoApiPost(c.GetTeamMembersRoute(teamId)+"/batch", TeamMembersToJson(members)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamMembersFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamMembersFromJson(r.Body), BuildResponse(r) } // RemoveTeamMember will remove a user from a team. func (c *Client4) RemoveTeamMember(teamId, userId string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetTeamMemberRoute(teamId, userId)); err != nil { + r, err := c.DoApiDelete(c.GetTeamMemberRoute(teamId, userId)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetTeamStats returns a team stats based on the team id string. // Must be authenticated. func (c *Client4) GetTeamStats(teamId, etag string) (*TeamStats, *Response) { - if r, err := c.DoApiGet(c.GetTeamStatsRoute(teamId), etag); err != nil { + r, err := c.DoApiGet(c.GetTeamStatsRoute(teamId), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamStatsFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamStatsFromJson(r.Body), BuildResponse(r) } // GetTotalUsersStats returns a total system user stats. // Must be authenticated. func (c *Client4) GetTotalUsersStats(etag string) (*UsersStats, *Response) { - if r, err := c.DoApiGet(c.GetTotalUsersStatsRoute(), etag); err != nil { + r, err := c.DoApiGet(c.GetTotalUsersStatsRoute(), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UsersStatsFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UsersStatsFromJson(r.Body), BuildResponse(r) } // GetTeamUnread will return a TeamUnread object that contains the amount of // unread messages and mentions the user has for the specified team. // Must be authenticated. func (c *Client4) GetTeamUnread(teamId, userId string) (*TeamUnread, *Response) { - if r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetTeamRoute(teamId)+"/unread", ""); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetTeamRoute(teamId)+"/unread", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamUnreadFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamUnreadFromJson(r.Body), BuildResponse(r) } // ImportTeam will import an exported team from other app into a existing team. @@ -1520,21 +1562,30 @@ func (c *Client4) ImportTeam(data []byte, filesize int, importFrom, filename, te body := &bytes.Buffer{} writer := multipart.NewWriter(body) - if part, err := writer.CreateFormFile("file", filename); err != nil { - return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)} - } else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { + part, err := writer.CreateFormFile("file", filename) + if err != nil { return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)} } - if part, err := writer.CreateFormField("filesize"); err != nil { - return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file_size.app_error", nil, err.Error(), http.StatusBadRequest)} - } else if _, err = io.Copy(part, strings.NewReader(strconv.Itoa(filesize))); err != nil { + if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { + return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)} + } + + part, err = writer.CreateFormField("filesize") + if err != nil { return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file_size.app_error", nil, err.Error(), http.StatusBadRequest)} } - if part, err := writer.CreateFormField("importFrom"); err != nil { + if _, err = io.Copy(part, strings.NewReader(strconv.Itoa(filesize))); err != nil { + return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file_size.app_error", nil, err.Error(), http.StatusBadRequest)} + } + + part, err = writer.CreateFormField("importFrom") + if err != nil { return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.import_from.app_error", nil, err.Error(), http.StatusBadRequest)} - } else if _, err = io.Copy(part, strings.NewReader(importFrom)); err != nil { + } + + if _, err := io.Copy(part, strings.NewReader(importFrom)); err != nil { return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.import_from.app_error", nil, err.Error(), http.StatusBadRequest)} } @@ -1547,37 +1598,39 @@ func (c *Client4) ImportTeam(data []byte, filesize int, importFrom, filename, te // InviteUsersToTeam invite users by email to the team. func (c *Client4) InviteUsersToTeam(teamId string, userEmails []string) (bool, *Response) { - if r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/invite/email", ArrayToJson(userEmails)); err != nil { + r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/invite/email", ArrayToJson(userEmails)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetTeamInviteInfo returns a team object from an invite id containing sanitized information. func (c *Client4) GetTeamInviteInfo(inviteId string) (*Team, *Response) { - if r, err := c.DoApiGet(c.GetTeamsRoute()+"/invite/"+inviteId, ""); err != nil { + r, err := c.DoApiGet(c.GetTeamsRoute()+"/invite/"+inviteId, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamFromJson(r.Body), BuildResponse(r) } -// SetTeamIcon sets team icon of the team +// SetTeamIcon sets team icon of the team. func (c *Client4) SetTeamIcon(teamId string, data []byte) (bool, *Response) { - body := &bytes.Buffer{} writer := multipart.NewWriter(body) - if part, err := writer.CreateFormFile("image", "teamIcon.png"); err != nil { - return false, &Response{Error: NewAppError("SetTeamIcon", "model.client.set_team_icon.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} - } else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { + part, err := writer.CreateFormFile("image", "teamIcon.png") + if err != nil { return false, &Response{Error: NewAppError("SetTeamIcon", "model.client.set_team_icon.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} } - if err := writer.Close(); err != nil { + if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { + return false, &Response{Error: NewAppError("SetTeamIcon", "model.client.set_team_icon.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} + } + + if err = writer.Close(); err != nil { return false, &Response{Error: NewAppError("SetTeamIcon", "model.client.set_team_icon.writer.app_error", nil, err.Error(), http.StatusBadRequest)} } @@ -1588,510 +1641,521 @@ func (c *Client4) SetTeamIcon(teamId string, data []byte) (bool, *Response) { rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } - if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil { + rp, err := c.HttpClient.Do(rq) + if err != nil || rp == nil { // set to http.StatusForbidden(403) return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetTeamRoute(teamId)+"/image", "model.client.connecting.app_error", nil, err.Error(), 403)} - } else { - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } else { - return CheckStatusOK(rp), BuildResponse(rp) - } } + defer closeBody(rp) + + if rp.StatusCode >= 300 { + return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) + } + + return CheckStatusOK(rp), BuildResponse(rp) } -// GetTeamIcon gets the team icon of the team +// GetTeamIcon gets the team icon of the team. func (c *Client4) GetTeamIcon(teamId, etag string) ([]byte, *Response) { - if r, err := c.DoApiGet(c.GetTeamRoute(teamId)+"/image", etag); err != nil { - return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - - if data, err := ioutil.ReadAll(r.Body); err != nil { - return nil, BuildErrorResponse(r, NewAppError("GetTeamIcon", "model.client.get_team_icon.app_error", nil, err.Error(), r.StatusCode)) - } else { - return data, BuildResponse(r) - } + r, appErr := c.DoApiGet(c.GetTeamRoute(teamId)+"/image", etag) + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) } + defer closeBody(r) + + data, err := ioutil.ReadAll(r.Body) + if err != nil { + return nil, BuildErrorResponse(r, NewAppError("GetTeamIcon", "model.client.get_team_icon.app_error", nil, err.Error(), r.StatusCode)) + } + return data, BuildResponse(r) } // RemoveTeamIcon updates LastTeamIconUpdate to 0 which indicates team icon is removed. func (c *Client4) RemoveTeamIcon(teamId string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetTeamRoute(teamId) + "/image"); err != nil { + r, err := c.DoApiDelete(c.GetTeamRoute(teamId) + "/image") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // Channel Section // CreateChannel creates a channel based on the provided channel struct. func (c *Client4) CreateChannel(channel *Channel) (*Channel, *Response) { - if r, err := c.DoApiPost(c.GetChannelsRoute(), channel.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetChannelsRoute(), channel.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelFromJson(r.Body), BuildResponse(r) } -// UpdateChannel update a channel based on the provided channel struct. +// UpdateChannel updates a channel based on the provided channel struct. func (c *Client4) UpdateChannel(channel *Channel) (*Channel, *Response) { - if r, err := c.DoApiPut(c.GetChannelRoute(channel.Id), channel.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetChannelRoute(channel.Id), channel.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelFromJson(r.Body), BuildResponse(r) } // PatchChannel partially updates a channel. Any missing fields are not updated. func (c *Client4) PatchChannel(channelId string, patch *ChannelPatch) (*Channel, *Response) { - if r, err := c.DoApiPut(c.GetChannelRoute(channelId)+"/patch", patch.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetChannelRoute(channelId)+"/patch", patch.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelFromJson(r.Body), BuildResponse(r) } // ConvertChannelToPrivate converts public to private channel. func (c *Client4) ConvertChannelToPrivate(channelId string) (*Channel, *Response) { - if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/convert", ""); err != nil { + r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/convert", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelFromJson(r.Body), BuildResponse(r) } // RestoreChannel restores a previously deleted channel. Any missing fields are not updated. func (c *Client4) RestoreChannel(channelId string) (*Channel, *Response) { - if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/restore", ""); err != nil { + r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/restore", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelFromJson(r.Body), BuildResponse(r) } // CreateDirectChannel creates a direct message channel based on the two user // ids provided. func (c *Client4) CreateDirectChannel(userId1, userId2 string) (*Channel, *Response) { requestBody := []string{userId1, userId2} - if r, err := c.DoApiPost(c.GetChannelsRoute()+"/direct", ArrayToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetChannelsRoute()+"/direct", ArrayToJson(requestBody)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelFromJson(r.Body), BuildResponse(r) } -// CreateGroupChannel creates a group message channel based on userIds provided +// CreateGroupChannel creates a group message channel based on userIds provided. func (c *Client4) CreateGroupChannel(userIds []string) (*Channel, *Response) { - if r, err := c.DoApiPost(c.GetChannelsRoute()+"/group", ArrayToJson(userIds)); err != nil { + r, err := c.DoApiPost(c.GetChannelsRoute()+"/group", ArrayToJson(userIds)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelFromJson(r.Body), BuildResponse(r) } // GetChannel returns a channel based on the provided channel id string. func (c *Client4) GetChannel(channelId, etag string) (*Channel, *Response) { - if r, err := c.DoApiGet(c.GetChannelRoute(channelId), etag); err != nil { + r, err := c.DoApiGet(c.GetChannelRoute(channelId), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelFromJson(r.Body), BuildResponse(r) } // GetChannelStats returns statistics for a channel. func (c *Client4) GetChannelStats(channelId string, etag string) (*ChannelStats, *Response) { - if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/stats", etag); err != nil { + r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/stats", etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelStatsFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelStatsFromJson(r.Body), BuildResponse(r) +} + +// GetChannelMembersTimezones gets a list of timezones for a channel. +func (c *Client4) GetChannelMembersTimezones(channelId string) ([]string, *Response) { + r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/timezones", "") + if err != nil { + return nil, BuildErrorResponse(r, err) + } + defer closeBody(r) + return ArrayFromJson(r.Body), BuildResponse(r) } // GetPinnedPosts gets a list of pinned posts. func (c *Client4) GetPinnedPosts(channelId string, etag string) (*PostList, *Response) { - if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/pinned", etag); err != nil { + r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/pinned", etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostListFromJson(r.Body), BuildResponse(r) } // GetPublicChannelsForTeam returns a list of public channels based on the provided team id string. func (c *Client4) GetPublicChannelsForTeam(teamId string, page int, perPage int, etag string) ([]*Channel, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+query, etag); err != nil { + r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelSliceFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelSliceFromJson(r.Body), BuildResponse(r) } // GetDeletedChannelsForTeam returns a list of public channels based on the provided team id string. func (c *Client4) GetDeletedChannelsForTeam(teamId string, page int, perPage int, etag string) ([]*Channel, *Response) { query := fmt.Sprintf("/deleted?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+query, etag); err != nil { + r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelSliceFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelSliceFromJson(r.Body), BuildResponse(r) } -// GetPublicChannelsByIdsForTeam returns a list of public channels based on provided team id string +// GetPublicChannelsByIdsForTeam returns a list of public channels based on provided team id string. func (c *Client4) GetPublicChannelsByIdsForTeam(teamId string, channelIds []string) ([]*Channel, *Response) { - if r, err := c.DoApiPost(c.GetChannelsForTeamRoute(teamId)+"/ids", ArrayToJson(channelIds)); err != nil { + r, err := c.DoApiPost(c.GetChannelsForTeamRoute(teamId)+"/ids", ArrayToJson(channelIds)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelSliceFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelSliceFromJson(r.Body), BuildResponse(r) } // GetChannelsForTeamForUser returns a list channels of on a team for a user. func (c *Client4) GetChannelsForTeamForUser(teamId, userId, etag string) ([]*Channel, *Response) { - if r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetTeamRoute(teamId)+"/channels", etag); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetTeamRoute(teamId)+"/channels", etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelSliceFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelSliceFromJson(r.Body), BuildResponse(r) } // SearchChannels returns the channels on a team matching the provided search term. func (c *Client4) SearchChannels(teamId string, search *ChannelSearch) ([]*Channel, *Response) { - if r, err := c.DoApiPost(c.GetChannelsForTeamRoute(teamId)+"/search", search.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetChannelsForTeamRoute(teamId)+"/search", search.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelSliceFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelSliceFromJson(r.Body), BuildResponse(r) } // DeleteChannel deletes channel based on the provided channel id string. func (c *Client4) DeleteChannel(channelId string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetChannelRoute(channelId)); err != nil { + r, err := c.DoApiDelete(c.GetChannelRoute(channelId)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetChannelByName returns a channel based on the provided channel name and team id strings. func (c *Client4) GetChannelByName(channelName, teamId string, etag string) (*Channel, *Response) { - if r, err := c.DoApiGet(c.GetChannelByNameRoute(channelName, teamId), etag); err != nil { + r, err := c.DoApiGet(c.GetChannelByNameRoute(channelName, teamId), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelFromJson(r.Body), BuildResponse(r) } +// GetChannelByNameIncludeDeleted returns a channel based on the provided channel name and team id strings. Other then GetChannelByName it will also return deleted channels. func (c *Client4) GetChannelByNameIncludeDeleted(channelName, teamId string, etag string) (*Channel, *Response) { - if r, err := c.DoApiGet(c.GetChannelByNameRoute(channelName, teamId)+"?include_deleted=true", etag); err != nil { + r, err := c.DoApiGet(c.GetChannelByNameRoute(channelName, teamId)+"?include_deleted=true", etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelFromJson(r.Body), BuildResponse(r) } // GetChannelByNameForTeamName returns a channel based on the provided channel name and team name strings. func (c *Client4) GetChannelByNameForTeamName(channelName, teamName string, etag string) (*Channel, *Response) { - if r, err := c.DoApiGet(c.GetChannelByNameForTeamNameRoute(channelName, teamName), etag); err != nil { + r, err := c.DoApiGet(c.GetChannelByNameForTeamNameRoute(channelName, teamName), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelFromJson(r.Body), BuildResponse(r) } +// GetChannelByNameForTeamNameIncludeDeleted returns a channel based on the provided channel name and team name strings. Other then GetChannelByNameForTeamName it will also return deleted channels. func (c *Client4) GetChannelByNameForTeamNameIncludeDeleted(channelName, teamName string, etag string) (*Channel, *Response) { - if r, err := c.DoApiGet(c.GetChannelByNameForTeamNameRoute(channelName, teamName)+"?include_deleted=true", etag); err != nil { + r, err := c.DoApiGet(c.GetChannelByNameForTeamNameRoute(channelName, teamName)+"?include_deleted=true", etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelFromJson(r.Body), BuildResponse(r) } // GetChannelMembers gets a page of channel members. func (c *Client4) GetChannelMembers(channelId string, page, perPage int, etag string) (*ChannelMembers, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetChannelMembersRoute(channelId)+query, etag); err != nil { + r, err := c.DoApiGet(c.GetChannelMembersRoute(channelId)+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelMembersFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelMembersFromJson(r.Body), BuildResponse(r) } // GetChannelMembersByIds gets the channel members in a channel for a list of user ids. func (c *Client4) GetChannelMembersByIds(channelId string, userIds []string) (*ChannelMembers, *Response) { - if r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"/ids", ArrayToJson(userIds)); err != nil { + r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"/ids", ArrayToJson(userIds)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelMembersFromJson(r.Body), BuildResponse(r) - } + defer closeBody(r) + return ChannelMembersFromJson(r.Body), BuildResponse(r) } // GetChannelMember gets a channel member. func (c *Client4) GetChannelMember(channelId, userId, etag string) (*ChannelMember, *Response) { - if r, err := c.DoApiGet(c.GetChannelMemberRoute(channelId, userId), etag); err != nil { + r, err := c.DoApiGet(c.GetChannelMemberRoute(channelId, userId), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelMemberFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelMemberFromJson(r.Body), BuildResponse(r) } // GetChannelMembersForUser gets all the channel members for a user on a team. func (c *Client4) GetChannelMembersForUser(userId, teamId, etag string) (*ChannelMembers, *Response) { - if r, err := c.DoApiGet(fmt.Sprintf(c.GetUserRoute(userId)+"/teams/%v/channels/members", teamId), etag); err != nil { + r, err := c.DoApiGet(fmt.Sprintf(c.GetUserRoute(userId)+"/teams/%v/channels/members", teamId), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelMembersFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelMembersFromJson(r.Body), BuildResponse(r) } // ViewChannel performs a view action for a user. Synonymous with switching channels or marking channels as read by a user. func (c *Client4) ViewChannel(userId string, view *ChannelView) (*ChannelViewResponse, *Response) { url := fmt.Sprintf(c.GetChannelsRoute()+"/members/%v/view", userId) - if r, err := c.DoApiPost(url, view.ToJson()); err != nil { + r, err := c.DoApiPost(url, view.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelViewResponseFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelViewResponseFromJson(r.Body), BuildResponse(r) } // GetChannelUnread will return a ChannelUnread object that contains the number of // unread messages and mentions for a user. func (c *Client4) GetChannelUnread(channelId, userId string) (*ChannelUnread, *Response) { - if r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetChannelRoute(channelId)+"/unread", ""); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetChannelRoute(channelId)+"/unread", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelUnreadFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelUnreadFromJson(r.Body), BuildResponse(r) } // UpdateChannelRoles will update the roles on a channel for a user. func (c *Client4) UpdateChannelRoles(channelId, userId, roles string) (bool, *Response) { requestBody := map[string]string{"roles": roles} - if r, err := c.DoApiPut(c.GetChannelMemberRoute(channelId, userId)+"/roles", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPut(c.GetChannelMemberRoute(channelId, userId)+"/roles", MapToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // UpdateChannelMemberSchemeRoles will update the scheme-derived roles on a channel for a user. func (c *Client4) UpdateChannelMemberSchemeRoles(channelId string, userId string, schemeRoles *SchemeRoles) (bool, *Response) { - if r, err := c.DoApiPut(c.GetChannelMemberRoute(channelId, userId)+"/schemeRoles", schemeRoles.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetChannelMemberRoute(channelId, userId)+"/schemeRoles", schemeRoles.ToJson()) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // UpdateChannelNotifyProps will update the notification properties on a channel for a user. func (c *Client4) UpdateChannelNotifyProps(channelId, userId string, props map[string]string) (bool, *Response) { - if r, err := c.DoApiPut(c.GetChannelMemberRoute(channelId, userId)+"/notify_props", MapToJson(props)); err != nil { + r, err := c.DoApiPut(c.GetChannelMemberRoute(channelId, userId)+"/notify_props", MapToJson(props)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // AddChannelMember adds user to channel and return a channel member. func (c *Client4) AddChannelMember(channelId, userId string) (*ChannelMember, *Response) { requestBody := map[string]string{"user_id": userId} - if r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"", MapToJson(requestBody)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelMemberFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelMemberFromJson(r.Body), BuildResponse(r) } // AddChannelMemberWithRootId adds user to channel and return a channel member. Post add to channel message has the postRootId. func (c *Client4) AddChannelMemberWithRootId(channelId, userId, postRootId string) (*ChannelMember, *Response) { requestBody := map[string]string{"user_id": userId, "post_root_id": postRootId} - if r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"", MapToJson(requestBody)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelMemberFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelMemberFromJson(r.Body), BuildResponse(r) } // RemoveUserFromChannel will delete the channel member object for a user, effectively removing the user from a channel. func (c *Client4) RemoveUserFromChannel(channelId, userId string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetChannelMemberRoute(channelId, userId)); err != nil { + r, err := c.DoApiDelete(c.GetChannelMemberRoute(channelId, userId)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } -// AutocompleteChannelsForTeam will return an ordered list of channels autocomplete suggestions +// AutocompleteChannelsForTeam will return an ordered list of channels autocomplete suggestions. func (c *Client4) AutocompleteChannelsForTeam(teamId, name string) (*ChannelList, *Response) { query := fmt.Sprintf("?name=%v", name) - if r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+"/autocomplete"+query, ""); err != nil { + r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+"/autocomplete"+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelListFromJson(r.Body), BuildResponse(r) } -// AutocompleteChannelsForTeamForSearch will return an ordered list of your channels autocomplete suggestions +// AutocompleteChannelsForTeamForSearch will return an ordered list of your channels autocomplete suggestions. func (c *Client4) AutocompleteChannelsForTeamForSearch(teamId, name string) (*ChannelList, *Response) { query := fmt.Sprintf("?name=%v", name) - if r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+"/search_autocomplete"+query, ""); err != nil { + r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+"/search_autocomplete"+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelListFromJson(r.Body), BuildResponse(r) } // Post Section // CreatePost creates a post based on the provided post struct. func (c *Client4) CreatePost(post *Post) (*Post, *Response) { - if r, err := c.DoApiPost(c.GetPostsRoute(), post.ToUnsanitizedJson()); err != nil { + r, err := c.DoApiPost(c.GetPostsRoute(), post.ToUnsanitizedJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostFromJson(r.Body), BuildResponse(r) } -// CreatePostEphemeral creates a ephemeral post based on the provided post struct which is send to the given user id +// CreatePostEphemeral creates a ephemeral post based on the provided post struct which is send to the given user id. func (c *Client4) CreatePostEphemeral(post *PostEphemeral) (*Post, *Response) { - if r, err := c.DoApiPost(c.GetPostsEphemeralRoute(), post.ToUnsanitizedJson()); err != nil { + r, err := c.DoApiPost(c.GetPostsEphemeralRoute(), post.ToUnsanitizedJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostFromJson(r.Body), BuildResponse(r) } // UpdatePost updates a post based on the provided post struct. func (c *Client4) UpdatePost(postId string, post *Post) (*Post, *Response) { - if r, err := c.DoApiPut(c.GetPostRoute(postId), post.ToUnsanitizedJson()); err != nil { + r, err := c.DoApiPut(c.GetPostRoute(postId), post.ToUnsanitizedJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostFromJson(r.Body), BuildResponse(r) } // PatchPost partially updates a post. Any missing fields are not updated. func (c *Client4) PatchPost(postId string, patch *PostPatch) (*Post, *Response) { - if r, err := c.DoApiPut(c.GetPostRoute(postId)+"/patch", patch.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetPostRoute(postId)+"/patch", patch.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostFromJson(r.Body), BuildResponse(r) } // PinPost pin a post based on provided post id string. func (c *Client4) PinPost(postId string) (bool, *Response) { - if r, err := c.DoApiPost(c.GetPostRoute(postId)+"/pin", ""); err != nil { + r, err := c.DoApiPost(c.GetPostRoute(postId)+"/pin", "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // UnpinPost unpin a post based on provided post id string. func (c *Client4) UnpinPost(postId string) (bool, *Response) { - if r, err := c.DoApiPost(c.GetPostRoute(postId)+"/unpin", ""); err != nil { + r, err := c.DoApiPost(c.GetPostRoute(postId)+"/unpin", "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetPost gets a single post. func (c *Client4) GetPost(postId string, etag string) (*Post, *Response) { - if r, err := c.DoApiGet(c.GetPostRoute(postId), etag); err != nil { + r, err := c.DoApiGet(c.GetPostRoute(postId), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostFromJson(r.Body), BuildResponse(r) } // DeletePost deletes a post from the provided post id string. func (c *Client4) DeletePost(postId string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetPostRoute(postId)); err != nil { + r, err := c.DoApiDelete(c.GetPostRoute(postId)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetPostThread gets a post with all the other posts in the same thread. func (c *Client4) GetPostThread(postId string, etag string) (*PostList, *Response) { - if r, err := c.DoApiGet(c.GetPostRoute(postId)+"/thread", etag); err != nil { + r, err := c.DoApiGet(c.GetPostRoute(postId)+"/thread", etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostListFromJson(r.Body), BuildResponse(r) } // GetPostsForChannel gets a page of posts with an array for ordering for a channel. func (c *Client4) GetPostsForChannel(channelId string, page, perPage int, etag string) (*PostList, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag); err != nil { + r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostListFromJson(r.Body), BuildResponse(r) } // GetFlaggedPostsForUser returns flagged posts of a user based on user id string. func (c *Client4) GetFlaggedPostsForUser(userId string, page int, perPage int) (*PostList, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/posts/flagged"+query, ""); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId)+"/posts/flagged"+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostListFromJson(r.Body), BuildResponse(r) } // GetFlaggedPostsForUserInTeam returns flagged posts in team of a user based on user id string. @@ -2101,12 +2165,12 @@ func (c *Client4) GetFlaggedPostsForUserInTeam(userId string, teamId string, pag } query := fmt.Sprintf("?team_id=%v&page=%v&per_page=%v", teamId, page, perPage) - if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/posts/flagged"+query, ""); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId)+"/posts/flagged"+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostListFromJson(r.Body), BuildResponse(r) } // GetFlaggedPostsForUserInChannel returns flagged posts in channel of a user based on user id string. @@ -2116,45 +2180,45 @@ func (c *Client4) GetFlaggedPostsForUserInChannel(userId string, channelId strin } query := fmt.Sprintf("?channel_id=%v&page=%v&per_page=%v", channelId, page, perPage) - if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/posts/flagged"+query, ""); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId)+"/posts/flagged"+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostListFromJson(r.Body), BuildResponse(r) } // GetPostsSince gets posts created after a specified time as Unix time in milliseconds. func (c *Client4) GetPostsSince(channelId string, time int64) (*PostList, *Response) { query := fmt.Sprintf("?since=%v", time) - if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, ""); err != nil { + r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostListFromJson(r.Body), BuildResponse(r) } // GetPostsAfter gets a page of posts that were posted after the post provided. func (c *Client4) GetPostsAfter(channelId, postId string, page, perPage int, etag string) (*PostList, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v&after=%v", page, perPage, postId) - if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag); err != nil { + r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostListFromJson(r.Body), BuildResponse(r) } // GetPostsBefore gets a page of posts that were posted before the post provided. func (c *Client4) GetPostsBefore(channelId, postId string, page, perPage int, etag string) (*PostList, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v&before=%v", page, perPage, postId) - if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag); err != nil { + r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostListFromJson(r.Body), BuildResponse(r) } // SearchPosts returns any posts with matching terms string. @@ -2166,35 +2230,64 @@ func (c *Client4) SearchPosts(teamId string, terms string, isOrSearch bool) (*Po return c.SearchPostsWithParams(teamId, ¶ms) } -// SearchPosts returns any posts with matching terms string. +// SearchPostsWithParams returns any posts with matching terms string. func (c *Client4) SearchPostsWithParams(teamId string, params *SearchParameter) (*PostList, *Response) { - if r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/posts/search", params.SearchParameterToJson()); err != nil { + r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/posts/search", params.SearchParameterToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostListFromJson(r.Body), BuildResponse(r) } -// SearchPosts returns any posts with matching terms string, including . +// SearchPostsWithMatches returns any posts with matching terms string, including. func (c *Client4) SearchPostsWithMatches(teamId string, terms string, isOrSearch bool) (*PostSearchResults, *Response) { requestBody := map[string]interface{}{"terms": terms, "is_or_search": isOrSearch} - if r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/posts/search", StringInterfaceToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/posts/search", StringInterfaceToJson(requestBody)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostSearchResultsFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostSearchResultsFromJson(r.Body), BuildResponse(r) } // DoPostAction performs a post action. func (c *Client4) DoPostAction(postId, actionId string) (bool, *Response) { - if r, err := c.DoApiPost(c.GetPostRoute(postId)+"/actions/"+actionId, ""); err != nil { + r, err := c.DoApiPost(c.GetPostRoute(postId)+"/actions/"+actionId, "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) +} + +// OpenInteractiveDialog sends a WebSocket event to a user's clients to +// open interactive dialogs, based on the provided trigger ID and other +// provided data. Used with interactive message buttons, menus and +// slash commands. +func (c *Client4) OpenInteractiveDialog(request OpenDialogRequest) (bool, *Response) { + b, _ := json.Marshal(request) + r, err := c.DoApiPost("/actions/dialogs/open", string(b)) + if err != nil { + return false, BuildErrorResponse(r, err) + } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) +} + +// SubmitInteractiveDialog will submit the provided dialog data to the integration +// configured by the URL. Used with the interactive dialogs integration feature. +func (c *Client4) SubmitInteractiveDialog(request SubmitDialogRequest) (*SubmitDialogResponse, *Response) { + b, _ := json.Marshal(request) + r, err := c.DoApiPost("/actions/dialogs/submit", string(b)) + if err != nil { + return nil, BuildErrorResponse(r, err) + } + defer closeBody(r) + + var resp SubmitDialogResponse + json.NewDecoder(r.Body).Decode(&resp) + return &resp, BuildResponse(r) } // File Section @@ -2205,15 +2298,21 @@ func (c *Client4) UploadFile(data []byte, channelId string, filename string) (*F body := &bytes.Buffer{} writer := multipart.NewWriter(body) - if part, err := writer.CreateFormFile("files", filename); err != nil { - return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)} - } else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { + part, err := writer.CreateFormFile("files", filename) + if err != nil { return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)} } - if part, err := writer.CreateFormField("channel_id"); err != nil { + if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { + return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)} + } + + part, err = writer.CreateFormField("channel_id") + if err != nil { return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.channel_id.app_error", nil, err.Error(), http.StatusBadRequest)} - } else if _, err = io.Copy(part, strings.NewReader(channelId)); err != nil { + } + + if _, err := io.Copy(part, strings.NewReader(channelId)); err != nil { return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.channel_id.app_error", nil, err.Error(), http.StatusBadRequest)} } @@ -2232,242 +2331,242 @@ func (c *Client4) UploadFileAsRequestBody(data []byte, channelId string, filenam // GetFile gets the bytes for a file by id. func (c *Client4) GetFile(fileId string) ([]byte, *Response) { - if r, err := c.DoApiGet(c.GetFileRoute(fileId), ""); err != nil { - return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - - if data, err := ioutil.ReadAll(r.Body); err != nil { - return nil, BuildErrorResponse(r, NewAppError("GetFile", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } else { - return data, BuildResponse(r) - } + r, appErr := c.DoApiGet(c.GetFileRoute(fileId), "") + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) } + defer closeBody(r) + + data, err := ioutil.ReadAll(r.Body) + if err != nil { + return nil, BuildErrorResponse(r, NewAppError("GetFile", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) + } + return data, BuildResponse(r) } -// DownloadFile gets the bytes for a file by id, optionally adding headers to force the browser to download it +// DownloadFile gets the bytes for a file by id, optionally adding headers to force the browser to download it. func (c *Client4) DownloadFile(fileId string, download bool) ([]byte, *Response) { - if r, err := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("?download=%v", download), ""); err != nil { - return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - - if data, err := ioutil.ReadAll(r.Body); err != nil { - return nil, BuildErrorResponse(r, NewAppError("DownloadFile", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } else { - return data, BuildResponse(r) - } + r, appErr := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("?download=%v", download), "") + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) } + defer closeBody(r) + + data, err := ioutil.ReadAll(r.Body) + if err != nil { + return nil, BuildErrorResponse(r, NewAppError("DownloadFile", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) + } + return data, BuildResponse(r) } // GetFileThumbnail gets the bytes for a file by id. func (c *Client4) GetFileThumbnail(fileId string) ([]byte, *Response) { - if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/thumbnail", ""); err != nil { - return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - - if data, err := ioutil.ReadAll(r.Body); err != nil { - return nil, BuildErrorResponse(r, NewAppError("GetFileThumbnail", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } else { - return data, BuildResponse(r) - } + r, appErr := c.DoApiGet(c.GetFileRoute(fileId)+"/thumbnail", "") + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) } + defer closeBody(r) + + data, err := ioutil.ReadAll(r.Body) + if err != nil { + return nil, BuildErrorResponse(r, NewAppError("GetFileThumbnail", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) + } + return data, BuildResponse(r) } // DownloadFileThumbnail gets the bytes for a file by id, optionally adding headers to force the browser to download it. func (c *Client4) DownloadFileThumbnail(fileId string, download bool) ([]byte, *Response) { - if r, err := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("/thumbnail?download=%v", download), ""); err != nil { - return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - - if data, err := ioutil.ReadAll(r.Body); err != nil { - return nil, BuildErrorResponse(r, NewAppError("DownloadFileThumbnail", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } else { - return data, BuildResponse(r) - } + r, appErr := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("/thumbnail?download=%v", download), "") + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) } + defer closeBody(r) + + data, err := ioutil.ReadAll(r.Body) + if err != nil { + return nil, BuildErrorResponse(r, NewAppError("DownloadFileThumbnail", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) + } + return data, BuildResponse(r) } // GetFileLink gets the public link of a file by id. func (c *Client4) GetFileLink(fileId string) (string, *Response) { - if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/link", ""); err != nil { + r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/link", "") + if err != nil { return "", BuildErrorResponse(r, err) - } else { - defer closeBody(r) - - return MapFromJson(r.Body)["link"], BuildResponse(r) } + defer closeBody(r) + return MapFromJson(r.Body)["link"], BuildResponse(r) } // GetFilePreview gets the bytes for a file by id. func (c *Client4) GetFilePreview(fileId string) ([]byte, *Response) { - if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/preview", ""); err != nil { - return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - - if data, err := ioutil.ReadAll(r.Body); err != nil { - return nil, BuildErrorResponse(r, NewAppError("GetFilePreview", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } else { - return data, BuildResponse(r) - } + r, appErr := c.DoApiGet(c.GetFileRoute(fileId)+"/preview", "") + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) } + defer closeBody(r) + + data, err := ioutil.ReadAll(r.Body) + if err != nil { + return nil, BuildErrorResponse(r, NewAppError("GetFilePreview", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) + } + return data, BuildResponse(r) } // DownloadFilePreview gets the bytes for a file by id. func (c *Client4) DownloadFilePreview(fileId string, download bool) ([]byte, *Response) { - if r, err := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("/preview?download=%v", download), ""); err != nil { - return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - - if data, err := ioutil.ReadAll(r.Body); err != nil { - return nil, BuildErrorResponse(r, NewAppError("DownloadFilePreview", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } else { - return data, BuildResponse(r) - } + r, appErr := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("/preview?download=%v", download), "") + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) } + defer closeBody(r) + + data, err := ioutil.ReadAll(r.Body) + if err != nil { + return nil, BuildErrorResponse(r, NewAppError("DownloadFilePreview", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) + } + return data, BuildResponse(r) } // GetFileInfo gets all the file info objects. func (c *Client4) GetFileInfo(fileId string) (*FileInfo, *Response) { - if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/info", ""); err != nil { + r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/info", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return FileInfoFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return FileInfoFromJson(r.Body), BuildResponse(r) } // GetFileInfosForPost gets all the file info objects attached to a post. func (c *Client4) GetFileInfosForPost(postId string, etag string) ([]*FileInfo, *Response) { - if r, err := c.DoApiGet(c.GetPostRoute(postId)+"/files/info", etag); err != nil { + r, err := c.DoApiGet(c.GetPostRoute(postId)+"/files/info", etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return FileInfosFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return FileInfosFromJson(r.Body), BuildResponse(r) } // General/System Section // GetPing will return ok if the running goRoutines are below the threshold and unhealthy for above. func (c *Client4) GetPing() (string, *Response) { - if r, err := c.DoApiGet(c.GetSystemRoute()+"/ping", ""); r != nil && r.StatusCode == 500 { + r, err := c.DoApiGet(c.GetSystemRoute()+"/ping", "") + if r != nil && r.StatusCode == 500 { defer r.Body.Close() return "unhealthy", BuildErrorResponse(r, err) - } else if err != nil { - return "", BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return MapFromJson(r.Body)["status"], BuildResponse(r) } + if err != nil { + return "", BuildErrorResponse(r, err) + } + defer closeBody(r) + return MapFromJson(r.Body)["status"], BuildResponse(r) } // TestEmail will attempt to connect to the configured SMTP server. func (c *Client4) TestEmail(config *Config) (bool, *Response) { - if r, err := c.DoApiPost(c.GetTestEmailRoute(), config.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetTestEmailRoute(), config.ToJson()) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // TestS3Connection will attempt to connect to the AWS S3. func (c *Client4) TestS3Connection(config *Config) (bool, *Response) { - if r, err := c.DoApiPost(c.GetTestS3Route(), config.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetTestS3Route(), config.ToJson()) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetConfig will retrieve the server config with some sanitized items. func (c *Client4) GetConfig() (*Config, *Response) { - if r, err := c.DoApiGet(c.GetConfigRoute(), ""); err != nil { + r, err := c.DoApiGet(c.GetConfigRoute(), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ConfigFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ConfigFromJson(r.Body), BuildResponse(r) } // ReloadConfig will reload the server configuration. func (c *Client4) ReloadConfig() (bool, *Response) { - if r, err := c.DoApiPost(c.GetConfigRoute()+"/reload", ""); err != nil { + r, err := c.DoApiPost(c.GetConfigRoute()+"/reload", "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetOldClientConfig will retrieve the parts of the server configuration needed by the // client, formatted in the old format. func (c *Client4) GetOldClientConfig(etag string) (map[string]string, *Response) { - if r, err := c.DoApiGet(c.GetConfigRoute()+"/client?format=old", etag); err != nil { + r, err := c.DoApiGet(c.GetConfigRoute()+"/client?format=old", etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return MapFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return MapFromJson(r.Body), BuildResponse(r) } // GetEnvironmentConfig will retrieve a map mirroring the server configuration where fields // are set to true if the corresponding config setting is set through an environment variable. // Settings that haven't been set through environment variables will be missing from the map. func (c *Client4) GetEnvironmentConfig() (map[string]interface{}, *Response) { - if r, err := c.DoApiGet(c.GetConfigRoute()+"/environment", ""); err != nil { + r, err := c.DoApiGet(c.GetConfigRoute()+"/environment", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return StringInterfaceFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return StringInterfaceFromJson(r.Body), BuildResponse(r) } // GetOldClientLicense will retrieve the parts of the server license needed by the // client, formatted in the old format. func (c *Client4) GetOldClientLicense(etag string) (map[string]string, *Response) { - if r, err := c.DoApiGet(c.GetLicenseRoute()+"/client?format=old", etag); err != nil { + r, err := c.DoApiGet(c.GetLicenseRoute()+"/client?format=old", etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return MapFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return MapFromJson(r.Body), BuildResponse(r) } // DatabaseRecycle will recycle the connections. Discard current connection and get new one. func (c *Client4) DatabaseRecycle() (bool, *Response) { - if r, err := c.DoApiPost(c.GetDatabaseRoute()+"/recycle", ""); err != nil { + r, err := c.DoApiPost(c.GetDatabaseRoute()+"/recycle", "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // InvalidateCaches will purge the cache and can affect the performance while is cleaning. func (c *Client4) InvalidateCaches() (bool, *Response) { - if r, err := c.DoApiPost(c.GetCacheRoute()+"/invalidate", ""); err != nil { + r, err := c.DoApiPost(c.GetCacheRoute()+"/invalidate", "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // UpdateConfig will update the server configuration. func (c *Client4) UpdateConfig(config *Config) (*Config, *Response) { - if r, err := c.DoApiPut(c.GetConfigRoute(), config.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetConfigRoute(), config.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ConfigFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ConfigFromJson(r.Body), BuildResponse(r) } // UploadLicenseFile will add a license file to the system. @@ -2475,13 +2574,16 @@ func (c *Client4) UploadLicenseFile(data []byte) (bool, *Response) { body := &bytes.Buffer{} writer := multipart.NewWriter(body) - if part, err := writer.CreateFormFile("license", "test-license.mattermost-license"); err != nil { - return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} - } else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { + part, err := writer.CreateFormFile("license", "test-license.mattermost-license") + if err != nil { return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} } - if err := writer.Close(); err != nil { + if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { + return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} + } + + if err = writer.Close(); err != nil { return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.set_profile_user.writer.app_error", nil, err.Error(), http.StatusBadRequest)} } @@ -2492,28 +2594,28 @@ func (c *Client4) UploadLicenseFile(data []byte) (bool, *Response) { rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } - if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil { + rp, err := c.HttpClient.Do(rq) + if err != nil || rp == nil { return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetLicenseRoute(), "model.client.connecting.app_error", nil, err.Error(), http.StatusForbidden)} - } else { - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } else { - return CheckStatusOK(rp), BuildResponse(rp) - } } + defer closeBody(rp) + + if rp.StatusCode >= 300 { + return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) + } + + return CheckStatusOK(rp), BuildResponse(rp) } // RemoveLicenseFile will remove the server license it exists. Note that this will // disable all enterprise features. func (c *Client4) RemoveLicenseFile() (bool, *Response) { - if r, err := c.DoApiDelete(c.GetLicenseRoute()); err != nil { + r, err := c.DoApiDelete(c.GetLicenseRoute()) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetAnalyticsOld will retrieve analytics using the old format. New format is not @@ -2522,238 +2624,241 @@ func (c *Client4) RemoveLicenseFile() (bool, *Response) { // to a specific team. func (c *Client4) GetAnalyticsOld(name, teamId string) (AnalyticsRows, *Response) { query := fmt.Sprintf("?name=%v&team_id=%v", name, teamId) - if r, err := c.DoApiGet(c.GetAnalyticsRoute()+"/old"+query, ""); err != nil { + r, err := c.DoApiGet(c.GetAnalyticsRoute()+"/old"+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return AnalyticsRowsFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return AnalyticsRowsFromJson(r.Body), BuildResponse(r) } // Webhooks Section // CreateIncomingWebhook creates an incoming webhook for a channel. func (c *Client4) CreateIncomingWebhook(hook *IncomingWebhook) (*IncomingWebhook, *Response) { - if r, err := c.DoApiPost(c.GetIncomingWebhooksRoute(), hook.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetIncomingWebhooksRoute(), hook.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return IncomingWebhookFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return IncomingWebhookFromJson(r.Body), BuildResponse(r) } // UpdateIncomingWebhook updates an incoming webhook for a channel. func (c *Client4) UpdateIncomingWebhook(hook *IncomingWebhook) (*IncomingWebhook, *Response) { - if r, err := c.DoApiPut(c.GetIncomingWebhookRoute(hook.Id), hook.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetIncomingWebhookRoute(hook.Id), hook.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return IncomingWebhookFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return IncomingWebhookFromJson(r.Body), BuildResponse(r) } // GetIncomingWebhooks returns a page of incoming webhooks on the system. Page counting starts at 0. func (c *Client4) GetIncomingWebhooks(page int, perPage int, etag string) ([]*IncomingWebhook, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetIncomingWebhooksRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetIncomingWebhooksRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return IncomingWebhookListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return IncomingWebhookListFromJson(r.Body), BuildResponse(r) } // GetIncomingWebhooksForTeam returns a page of incoming webhooks for a team. Page counting starts at 0. func (c *Client4) GetIncomingWebhooksForTeam(teamId string, page int, perPage int, etag string) ([]*IncomingWebhook, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v&team_id=%v", page, perPage, teamId) - if r, err := c.DoApiGet(c.GetIncomingWebhooksRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetIncomingWebhooksRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return IncomingWebhookListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return IncomingWebhookListFromJson(r.Body), BuildResponse(r) } -// GetIncomingWebhook returns an Incoming webhook given the hook ID +// GetIncomingWebhook returns an Incoming webhook given the hook ID. func (c *Client4) GetIncomingWebhook(hookID string, etag string) (*IncomingWebhook, *Response) { - if r, err := c.DoApiGet(c.GetIncomingWebhookRoute(hookID), etag); err != nil { + r, err := c.DoApiGet(c.GetIncomingWebhookRoute(hookID), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return IncomingWebhookFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return IncomingWebhookFromJson(r.Body), BuildResponse(r) } -// DeleteIncomingWebhook deletes and Incoming Webhook given the hook ID +// DeleteIncomingWebhook deletes and Incoming Webhook given the hook ID. func (c *Client4) DeleteIncomingWebhook(hookID string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetIncomingWebhookRoute(hookID)); err != nil { + r, err := c.DoApiDelete(c.GetIncomingWebhookRoute(hookID)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // CreateOutgoingWebhook creates an outgoing webhook for a team or channel. func (c *Client4) CreateOutgoingWebhook(hook *OutgoingWebhook) (*OutgoingWebhook, *Response) { - if r, err := c.DoApiPost(c.GetOutgoingWebhooksRoute(), hook.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetOutgoingWebhooksRoute(), hook.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OutgoingWebhookFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OutgoingWebhookFromJson(r.Body), BuildResponse(r) } // UpdateOutgoingWebhook creates an outgoing webhook for a team or channel. func (c *Client4) UpdateOutgoingWebhook(hook *OutgoingWebhook) (*OutgoingWebhook, *Response) { - if r, err := c.DoApiPut(c.GetOutgoingWebhookRoute(hook.Id), hook.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetOutgoingWebhookRoute(hook.Id), hook.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OutgoingWebhookFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OutgoingWebhookFromJson(r.Body), BuildResponse(r) } // GetOutgoingWebhooks returns a page of outgoing webhooks on the system. Page counting starts at 0. func (c *Client4) GetOutgoingWebhooks(page int, perPage int, etag string) ([]*OutgoingWebhook, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OutgoingWebhookListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OutgoingWebhookListFromJson(r.Body), BuildResponse(r) } // GetOutgoingWebhook outgoing webhooks on the system requested by Hook Id. func (c *Client4) GetOutgoingWebhook(hookId string) (*OutgoingWebhook, *Response) { - if r, err := c.DoApiGet(c.GetOutgoingWebhookRoute(hookId), ""); err != nil { + r, err := c.DoApiGet(c.GetOutgoingWebhookRoute(hookId), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OutgoingWebhookFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OutgoingWebhookFromJson(r.Body), BuildResponse(r) } // GetOutgoingWebhooksForChannel returns a page of outgoing webhooks for a channel. Page counting starts at 0. func (c *Client4) GetOutgoingWebhooksForChannel(channelId string, page int, perPage int, etag string) ([]*OutgoingWebhook, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v&channel_id=%v", page, perPage, channelId) - if r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OutgoingWebhookListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OutgoingWebhookListFromJson(r.Body), BuildResponse(r) } // GetOutgoingWebhooksForTeam returns a page of outgoing webhooks for a team. Page counting starts at 0. func (c *Client4) GetOutgoingWebhooksForTeam(teamId string, page int, perPage int, etag string) ([]*OutgoingWebhook, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v&team_id=%v", page, perPage, teamId) - if r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OutgoingWebhookListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OutgoingWebhookListFromJson(r.Body), BuildResponse(r) } // RegenOutgoingHookToken regenerate the outgoing webhook token. func (c *Client4) RegenOutgoingHookToken(hookId string) (*OutgoingWebhook, *Response) { - if r, err := c.DoApiPost(c.GetOutgoingWebhookRoute(hookId)+"/regen_token", ""); err != nil { + r, err := c.DoApiPost(c.GetOutgoingWebhookRoute(hookId)+"/regen_token", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OutgoingWebhookFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OutgoingWebhookFromJson(r.Body), BuildResponse(r) } // DeleteOutgoingWebhook delete the outgoing webhook on the system requested by Hook Id. func (c *Client4) DeleteOutgoingWebhook(hookId string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetOutgoingWebhookRoute(hookId)); err != nil { + r, err := c.DoApiDelete(c.GetOutgoingWebhookRoute(hookId)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // Preferences Section // GetPreferences returns the user's preferences. func (c *Client4) GetPreferences(userId string) (Preferences, *Response) { - if r, err := c.DoApiGet(c.GetPreferencesRoute(userId), ""); err != nil { + r, err := c.DoApiGet(c.GetPreferencesRoute(userId), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - preferences, _ := PreferencesFromJson(r.Body) - defer closeBody(r) - return preferences, BuildResponse(r) } + defer closeBody(r) + preferences, _ := PreferencesFromJson(r.Body) + return preferences, BuildResponse(r) } // UpdatePreferences saves the user's preferences. func (c *Client4) UpdatePreferences(userId string, preferences *Preferences) (bool, *Response) { - if r, err := c.DoApiPut(c.GetPreferencesRoute(userId), preferences.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetPreferencesRoute(userId), preferences.ToJson()) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return true, BuildResponse(r) } + defer closeBody(r) + return true, BuildResponse(r) } // DeletePreferences deletes the user's preferences. func (c *Client4) DeletePreferences(userId string, preferences *Preferences) (bool, *Response) { - if r, err := c.DoApiPost(c.GetPreferencesRoute(userId)+"/delete", preferences.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetPreferencesRoute(userId)+"/delete", preferences.ToJson()) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return true, BuildResponse(r) } + defer closeBody(r) + return true, BuildResponse(r) } // GetPreferencesByCategory returns the user's preferences from the provided category string. func (c *Client4) GetPreferencesByCategory(userId string, category string) (Preferences, *Response) { url := fmt.Sprintf(c.GetPreferencesRoute(userId)+"/%s", category) - if r, err := c.DoApiGet(url, ""); err != nil { + r, err := c.DoApiGet(url, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - preferences, _ := PreferencesFromJson(r.Body) - defer closeBody(r) - return preferences, BuildResponse(r) } + defer closeBody(r) + preferences, _ := PreferencesFromJson(r.Body) + return preferences, BuildResponse(r) } // GetPreferenceByCategoryAndName returns the user's preferences from the provided category and preference name string. func (c *Client4) GetPreferenceByCategoryAndName(userId string, category string, preferenceName string) (*Preference, *Response) { url := fmt.Sprintf(c.GetPreferencesRoute(userId)+"/%s/name/%v", category, preferenceName) - if r, err := c.DoApiGet(url, ""); err != nil { + r, err := c.DoApiGet(url, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PreferenceFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PreferenceFromJson(r.Body), BuildResponse(r) } // SAML Section // GetSamlMetadata returns metadata for the SAML configuration. func (c *Client4) GetSamlMetadata() (string, *Response) { - if r, err := c.DoApiGet(c.GetSamlRoute()+"/metadata", ""); err != nil { + r, err := c.DoApiGet(c.GetSamlRoute()+"/metadata", "") + if err != nil { return "", BuildErrorResponse(r, err) - } else { - defer closeBody(r) - buf := new(bytes.Buffer) - buf.ReadFrom(r.Body) - return buf.String(), BuildResponse(r) } + defer closeBody(r) + buf := new(bytes.Buffer) + _, _ = buf.ReadFrom(r.Body) + return buf.String(), BuildResponse(r) } func samlFileToMultipart(data []byte, filename string) ([]byte, *multipart.Writer, error) { body := &bytes.Buffer{} writer := multipart.NewWriter(body) - if part, err := writer.CreateFormFile("certificate", filename); err != nil { + part, err := writer.CreateFormFile("certificate", filename) + if err != nil { return nil, nil, err - } else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { + } + + if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { return nil, nil, err } @@ -2799,134 +2904,136 @@ func (c *Client4) UploadSamlPrivateCertificate(data []byte, filename string) (bo // DeleteSamlIdpCertificate deletes the SAML IDP certificate from the server and updates the config to not use it and disable SAML. func (c *Client4) DeleteSamlIdpCertificate() (bool, *Response) { - if r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/idp"); err != nil { + r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/idp") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // DeleteSamlPublicCertificate deletes the SAML IDP certificate from the server and updates the config to not use it and disable SAML. func (c *Client4) DeleteSamlPublicCertificate() (bool, *Response) { - if r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/public"); err != nil { + r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/public") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // DeleteSamlPrivateCertificate deletes the SAML IDP certificate from the server and updates the config to not use it and disable SAML. func (c *Client4) DeleteSamlPrivateCertificate() (bool, *Response) { - if r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/private"); err != nil { + r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/private") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetSamlCertificateStatus returns metadata for the SAML configuration. func (c *Client4) GetSamlCertificateStatus() (*SamlCertificateStatus, *Response) { - if r, err := c.DoApiGet(c.GetSamlRoute()+"/certificate/status", ""); err != nil { + r, err := c.DoApiGet(c.GetSamlRoute()+"/certificate/status", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return SamlCertificateStatusFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return SamlCertificateStatusFromJson(r.Body), BuildResponse(r) } // Compliance Section // CreateComplianceReport creates an incoming webhook for a channel. func (c *Client4) CreateComplianceReport(report *Compliance) (*Compliance, *Response) { - if r, err := c.DoApiPost(c.GetComplianceReportsRoute(), report.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetComplianceReportsRoute(), report.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ComplianceFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ComplianceFromJson(r.Body), BuildResponse(r) } // GetComplianceReports returns list of compliance reports. func (c *Client4) GetComplianceReports(page, perPage int) (Compliances, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetComplianceReportsRoute()+query, ""); err != nil { + r, err := c.DoApiGet(c.GetComplianceReportsRoute()+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CompliancesFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return CompliancesFromJson(r.Body), BuildResponse(r) } // GetComplianceReport returns a compliance report. func (c *Client4) GetComplianceReport(reportId string) (*Compliance, *Response) { - if r, err := c.DoApiGet(c.GetComplianceReportRoute(reportId), ""); err != nil { + r, err := c.DoApiGet(c.GetComplianceReportRoute(reportId), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ComplianceFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ComplianceFromJson(r.Body), BuildResponse(r) } // DownloadComplianceReport returns a full compliance report as a file. func (c *Client4) DownloadComplianceReport(reportId string) ([]byte, *Response) { - var rq *http.Request - rq, _ = http.NewRequest("GET", c.ApiUrl+c.GetComplianceReportRoute(reportId), nil) + rq, _ := http.NewRequest("GET", c.ApiUrl+c.GetComplianceReportRoute(reportId), nil) if len(c.AuthToken) > 0 { rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken) } - if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil { + rp, err := c.HttpClient.Do(rq) + if err != nil || rp == nil { return nil, &Response{Error: NewAppError("DownloadComplianceReport", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)} - } else { - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } else if data, err := ioutil.ReadAll(rp.Body); err != nil { - return nil, BuildErrorResponse(rp, NewAppError("DownloadComplianceReport", "model.client.read_file.app_error", nil, err.Error(), rp.StatusCode)) - } else { - return data, BuildResponse(rp) - } } + defer closeBody(rp) + + if rp.StatusCode >= 300 { + return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) + } + + data, err := ioutil.ReadAll(rp.Body) + if err != nil { + return nil, BuildErrorResponse(rp, NewAppError("DownloadComplianceReport", "model.client.read_file.app_error", nil, err.Error(), rp.StatusCode)) + } + + return data, BuildResponse(rp) } // Cluster Section // GetClusterStatus returns the status of all the configured cluster nodes. func (c *Client4) GetClusterStatus() ([]*ClusterInfo, *Response) { - if r, err := c.DoApiGet(c.GetClusterRoute()+"/status", ""); err != nil { + r, err := c.DoApiGet(c.GetClusterRoute()+"/status", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ClusterInfosFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ClusterInfosFromJson(r.Body), BuildResponse(r) } // LDAP Section // SyncLdap will force a sync with the configured LDAP server. func (c *Client4) SyncLdap() (bool, *Response) { - if r, err := c.DoApiPost(c.GetLdapRoute()+"/sync", ""); err != nil { + r, err := c.DoApiPost(c.GetLdapRoute()+"/sync", "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // TestLdap will attempt to connect to the configured LDAP server and return OK if configured // correctly. func (c *Client4) TestLdap() (bool, *Response) { - if r, err := c.DoApiPost(c.GetLdapRoute()+"/test", ""); err != nil { + r, err := c.DoApiPost(c.GetLdapRoute()+"/test", "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // Audits Section @@ -2934,31 +3041,43 @@ func (c *Client4) TestLdap() (bool, *Response) { // GetAudits returns a list of audits for the whole system. func (c *Client4) GetAudits(page int, perPage int, etag string) (Audits, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet("/audits"+query, etag); err != nil { + r, err := c.DoApiGet("/audits"+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return AuditsFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return AuditsFromJson(r.Body), BuildResponse(r) } // Brand Section // GetBrandImage retrieves the previously uploaded brand image. func (c *Client4) GetBrandImage() ([]byte, *Response) { - if r, err := c.DoApiGet(c.GetBrandRoute()+"/image", ""); err != nil { - return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - - if r.StatusCode >= 300 { - return nil, BuildErrorResponse(r, AppErrorFromJson(r.Body)) - } else if data, err := ioutil.ReadAll(r.Body); err != nil { - return nil, BuildErrorResponse(r, NewAppError("GetBrandImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } else { - return data, BuildResponse(r) - } + r, appErr := c.DoApiGet(c.GetBrandRoute()+"/image", "") + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) } + defer closeBody(r) + + if r.StatusCode >= 300 { + return nil, BuildErrorResponse(r, AppErrorFromJson(r.Body)) + } + + data, err := ioutil.ReadAll(r.Body) + if err != nil { + return nil, BuildErrorResponse(r, NewAppError("GetBrandImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) + } + + return data, BuildResponse(r) +} + +// DeleteBrandImage delets the brand image for the system. +func (c *Client4) DeleteBrandImage() *Response { + r, err := c.DoApiDelete(c.GetBrandRoute() + "/image") + if err != nil { + return BuildErrorResponse(r, err) + } + return BuildResponse(r) } // UploadBrandImage sets the brand image for the system. @@ -2966,13 +3085,16 @@ func (c *Client4) UploadBrandImage(data []byte) (bool, *Response) { body := &bytes.Buffer{} writer := multipart.NewWriter(body) - if part, err := writer.CreateFormFile("image", "brand.png"); err != nil { - return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} - } else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { + part, err := writer.CreateFormFile("image", "brand.png") + if err != nil { return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} } - if err := writer.Close(); err != nil { + if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { + return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} + } + + if err = writer.Close(); err != nil { return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.set_profile_user.writer.app_error", nil, err.Error(), http.StatusBadRequest)} } @@ -2983,17 +3105,17 @@ func (c *Client4) UploadBrandImage(data []byte) (bool, *Response) { rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } - if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil { + rp, err := c.HttpClient.Do(rq) + if err != nil || rp == nil { return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetBrandRoute()+"/image", "model.client.connecting.app_error", nil, err.Error(), http.StatusForbidden)} - } else { - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } else { - return CheckStatusOK(rp), BuildResponse(rp) - } } + defer closeBody(rp) + + if rp.StatusCode >= 300 { + return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) + } + + return CheckStatusOK(rp), BuildResponse(rp) } // Logs Section @@ -3001,129 +3123,129 @@ func (c *Client4) UploadBrandImage(data []byte) (bool, *Response) { // GetLogs page of logs as a string array. func (c *Client4) GetLogs(page, perPage int) ([]string, *Response) { query := fmt.Sprintf("?page=%v&logs_per_page=%v", page, perPage) - if r, err := c.DoApiGet("/logs"+query, ""); err != nil { + r, err := c.DoApiGet("/logs"+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ArrayFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ArrayFromJson(r.Body), BuildResponse(r) } // PostLog is a convenience Web Service call so clients can log messages into -// the server-side logs. For example we typically log javascript error messages -// into the server-side. It returns the log message if the logging was successful. +// the server-side logs. For example we typically log javascript error messages +// into the server-side. It returns the log message if the logging was successful. func (c *Client4) PostLog(message map[string]string) (map[string]string, *Response) { - if r, err := c.DoApiPost("/logs", MapToJson(message)); err != nil { + r, err := c.DoApiPost("/logs", MapToJson(message)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return MapFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return MapFromJson(r.Body), BuildResponse(r) } // OAuth Section // CreateOAuthApp will register a new OAuth 2.0 client application with Mattermost acting as an OAuth 2.0 service provider. func (c *Client4) CreateOAuthApp(app *OAuthApp) (*OAuthApp, *Response) { - if r, err := c.DoApiPost(c.GetOAuthAppsRoute(), app.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetOAuthAppsRoute(), app.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OAuthAppFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OAuthAppFromJson(r.Body), BuildResponse(r) } -// UpdateOAuthApp +// UpdateOAuthApp updates a page of registered OAuth 2.0 client applications with Mattermost acting as an OAuth 2.0 service provider. func (c *Client4) UpdateOAuthApp(app *OAuthApp) (*OAuthApp, *Response) { - if r, err := c.DoApiPut(c.GetOAuthAppRoute(app.Id), app.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetOAuthAppRoute(app.Id), app.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OAuthAppFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OAuthAppFromJson(r.Body), BuildResponse(r) } // GetOAuthApps gets a page of registered OAuth 2.0 client applications with Mattermost acting as an OAuth 2.0 service provider. func (c *Client4) GetOAuthApps(page, perPage int) ([]*OAuthApp, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetOAuthAppsRoute()+query, ""); err != nil { + r, err := c.DoApiGet(c.GetOAuthAppsRoute()+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OAuthAppListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OAuthAppListFromJson(r.Body), BuildResponse(r) } // GetOAuthApp gets a registered OAuth 2.0 client application with Mattermost acting as an OAuth 2.0 service provider. func (c *Client4) GetOAuthApp(appId string) (*OAuthApp, *Response) { - if r, err := c.DoApiGet(c.GetOAuthAppRoute(appId), ""); err != nil { + r, err := c.DoApiGet(c.GetOAuthAppRoute(appId), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OAuthAppFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OAuthAppFromJson(r.Body), BuildResponse(r) } // GetOAuthAppInfo gets a sanitized version of a registered OAuth 2.0 client application with Mattermost acting as an OAuth 2.0 service provider. func (c *Client4) GetOAuthAppInfo(appId string) (*OAuthApp, *Response) { - if r, err := c.DoApiGet(c.GetOAuthAppRoute(appId)+"/info", ""); err != nil { + r, err := c.DoApiGet(c.GetOAuthAppRoute(appId)+"/info", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OAuthAppFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OAuthAppFromJson(r.Body), BuildResponse(r) } // DeleteOAuthApp deletes a registered OAuth 2.0 client application. func (c *Client4) DeleteOAuthApp(appId string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetOAuthAppRoute(appId)); err != nil { + r, err := c.DoApiDelete(c.GetOAuthAppRoute(appId)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // RegenerateOAuthAppSecret regenerates the client secret for a registered OAuth 2.0 client application. func (c *Client4) RegenerateOAuthAppSecret(appId string) (*OAuthApp, *Response) { - if r, err := c.DoApiPost(c.GetOAuthAppRoute(appId)+"/regen_secret", ""); err != nil { + r, err := c.DoApiPost(c.GetOAuthAppRoute(appId)+"/regen_secret", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OAuthAppFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OAuthAppFromJson(r.Body), BuildResponse(r) } // GetAuthorizedOAuthAppsForUser gets a page of OAuth 2.0 client applications the user has authorized to use access their account. func (c *Client4) GetAuthorizedOAuthAppsForUser(userId string, page, perPage int) ([]*OAuthApp, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/oauth/apps/authorized"+query, ""); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId)+"/oauth/apps/authorized"+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OAuthAppListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OAuthAppListFromJson(r.Body), BuildResponse(r) } // AuthorizeOAuthApp will authorize an OAuth 2.0 client application to access a user's account and provide a redirect link to follow. func (c *Client4) AuthorizeOAuthApp(authRequest *AuthorizeRequest) (string, *Response) { - if r, err := c.DoApiRequest(http.MethodPost, c.Url+"/oauth/authorize", authRequest.ToJson(), ""); err != nil { + r, err := c.DoApiRequest(http.MethodPost, c.Url+"/oauth/authorize", authRequest.ToJson(), "") + if err != nil { return "", BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return MapFromJson(r.Body)["redirect"], BuildResponse(r) } + defer closeBody(r) + return MapFromJson(r.Body)["redirect"], BuildResponse(r) } // DeauthorizeOAuthApp will deauthorize an OAuth 2.0 client application from accessing a user's account. func (c *Client4) DeauthorizeOAuthApp(appId string) (bool, *Response) { requestData := map[string]string{"client_id": appId} - if r, err := c.DoApiRequest(http.MethodPost, c.Url+"/oauth/deauthorize", MapToJson(requestData), ""); err != nil { + r, err := c.DoApiRequest(http.MethodPost, c.Url+"/oauth/deauthorize", MapToJson(requestData), "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetOAuthAccessToken is a test helper function for the OAuth access token endpoint. @@ -3135,94 +3257,95 @@ func (c *Client4) GetOAuthAccessToken(data url.Values) (*AccessResponse, *Respon rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } - if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil { + rp, err := c.HttpClient.Do(rq) + if err != nil || rp == nil { return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.Url+"/oauth/access_token", "model.client.connecting.app_error", nil, err.Error(), 403)} - } else { - defer closeBody(rp) - if rp.StatusCode >= 300 { - return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } else { - return AccessResponseFromJson(rp.Body), BuildResponse(rp) - } } + defer closeBody(rp) + + if rp.StatusCode >= 300 { + return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) + } + + return AccessResponseFromJson(rp.Body), BuildResponse(rp) } // Elasticsearch Section -// TestElasticsearch will attempt to connect to the configured Elasticsearch server and return OK if configured +// TestElasticsearch will attempt to connect to the configured Elasticsearch server and return OK if configured. // correctly. func (c *Client4) TestElasticsearch() (bool, *Response) { - if r, err := c.DoApiPost(c.GetElasticsearchRoute()+"/test", ""); err != nil { + r, err := c.DoApiPost(c.GetElasticsearchRoute()+"/test", "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // PurgeElasticsearchIndexes immediately deletes all Elasticsearch indexes. func (c *Client4) PurgeElasticsearchIndexes() (bool, *Response) { - if r, err := c.DoApiPost(c.GetElasticsearchRoute()+"/purge_indexes", ""); err != nil { + r, err := c.DoApiPost(c.GetElasticsearchRoute()+"/purge_indexes", "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // Data Retention Section // GetDataRetentionPolicy will get the current server data retention policy details. func (c *Client4) GetDataRetentionPolicy() (*DataRetentionPolicy, *Response) { - if r, err := c.DoApiGet(c.GetDataRetentionRoute()+"/policy", ""); err != nil { + r, err := c.DoApiGet(c.GetDataRetentionRoute()+"/policy", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return DataRetentionPolicyFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return DataRetentionPolicyFromJson(r.Body), BuildResponse(r) } // Commands Section // CreateCommand will create a new command if the user have the right permissions. func (c *Client4) CreateCommand(cmd *Command) (*Command, *Response) { - if r, err := c.DoApiPost(c.GetCommandsRoute(), cmd.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetCommandsRoute(), cmd.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CommandFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return CommandFromJson(r.Body), BuildResponse(r) } -// UpdateCommand updates a command based on the provided Command struct +// UpdateCommand updates a command based on the provided Command struct. func (c *Client4) UpdateCommand(cmd *Command) (*Command, *Response) { - if r, err := c.DoApiPut(c.GetCommandRoute(cmd.Id), cmd.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetCommandRoute(cmd.Id), cmd.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CommandFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return CommandFromJson(r.Body), BuildResponse(r) } -// DeleteCommand deletes a command based on the provided command id string +// DeleteCommand deletes a command based on the provided command id string. func (c *Client4) DeleteCommand(commandId string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetCommandRoute(commandId)); err != nil { + r, err := c.DoApiDelete(c.GetCommandRoute(commandId)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // ListCommands will retrieve a list of commands available in the team. func (c *Client4) ListCommands(teamId string, customOnly bool) ([]*Command, *Response) { query := fmt.Sprintf("?team_id=%v&custom_only=%v", teamId, customOnly) - if r, err := c.DoApiGet(c.GetCommandsRoute()+query, ""); err != nil { + r, err := c.DoApiGet(c.GetCommandsRoute()+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CommandListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return CommandListFromJson(r.Body), BuildResponse(r) } // ExecuteCommand executes a given slash command. @@ -3231,98 +3354,84 @@ func (c *Client4) ExecuteCommand(channelId, command string) (*CommandResponse, * ChannelId: channelId, Command: command, } - if r, err := c.DoApiPost(c.GetCommandsRoute()+"/execute", commandArgs.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetCommandsRoute()+"/execute", commandArgs.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - - response, _ := CommandResponseFromJson(r.Body) - return response, BuildResponse(r) } + defer closeBody(r) + + response, _ := CommandResponseFromJson(r.Body) + return response, BuildResponse(r) } -// ExecuteCommand executes a given slash command against the specified team -// Use this when executing slash commands in a DM/GM, since the team id cannot be inferred in that case +// ExecuteCommandWithTeam executes a given slash command against the specified team. +// Use this when executing slash commands in a DM/GM, since the team id cannot be inferred in that case. func (c *Client4) ExecuteCommandWithTeam(channelId, teamId, command string) (*CommandResponse, *Response) { commandArgs := &CommandArgs{ ChannelId: channelId, TeamId: teamId, Command: command, } - if r, err := c.DoApiPost(c.GetCommandsRoute()+"/execute", commandArgs.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetCommandsRoute()+"/execute", commandArgs.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - - response, _ := CommandResponseFromJson(r.Body) - return response, BuildResponse(r) } + defer closeBody(r) + + response, _ := CommandResponseFromJson(r.Body) + return response, BuildResponse(r) } -// ListCommands will retrieve a list of commands available in the team. +// ListAutocompleteCommands will retrieve a list of commands available in the team. func (c *Client4) ListAutocompleteCommands(teamId string) ([]*Command, *Response) { - if r, err := c.DoApiGet(c.GetTeamAutoCompleteCommandsRoute(teamId), ""); err != nil { + r, err := c.DoApiGet(c.GetTeamAutoCompleteCommandsRoute(teamId), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CommandListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return CommandListFromJson(r.Body), BuildResponse(r) } // RegenCommandToken will create a new token if the user have the right permissions. func (c *Client4) RegenCommandToken(commandId string) (string, *Response) { - if r, err := c.DoApiPut(c.GetCommandRoute(commandId)+"/regen_token", ""); err != nil { + r, err := c.DoApiPut(c.GetCommandRoute(commandId)+"/regen_token", "") + if err != nil { return "", BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return MapFromJson(r.Body)["token"], BuildResponse(r) } + defer closeBody(r) + return MapFromJson(r.Body)["token"], BuildResponse(r) } // Status Section // GetUserStatus returns a user based on the provided user id string. func (c *Client4) GetUserStatus(userId, etag string) (*Status, *Response) { - if r, err := c.DoApiGet(c.GetUserStatusRoute(userId), etag); err != nil { + r, err := c.DoApiGet(c.GetUserStatusRoute(userId), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return StatusFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return StatusFromJson(r.Body), BuildResponse(r) } // GetUsersStatusesByIds returns a list of users status based on the provided user ids. func (c *Client4) GetUsersStatusesByIds(userIds []string) ([]*Status, *Response) { - if r, err := c.DoApiPost(c.GetUserStatusesRoute()+"/ids", ArrayToJson(userIds)); err != nil { + r, err := c.DoApiPost(c.GetUserStatusesRoute()+"/ids", ArrayToJson(userIds)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return StatusListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return StatusListFromJson(r.Body), BuildResponse(r) } // UpdateUserStatus sets a user's status based on the provided user id string. func (c *Client4) UpdateUserStatus(userId string, userStatus *Status) (*Status, *Response) { - if r, err := c.DoApiPut(c.GetUserStatusRoute(userId), userStatus.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetUserStatusRoute(userId), userStatus.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return StatusFromJson(r.Body), BuildResponse(r) - - } -} - -// Webrtc Section - -// GetWebrtcToken returns a valid token, stun server and turn server with credentials to -// use with the Mattermost WebRTC service. -func (c *Client4) GetWebrtcToken() (*WebrtcInfoResponse, *Response) { - if r, err := c.DoApiGet("/webrtc/token", ""); err != nil { - return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return WebrtcInfoResponseFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return StatusFromJson(r.Body), BuildResponse(r) } // Emoji Section @@ -3334,9 +3443,12 @@ func (c *Client4) CreateEmoji(emoji *Emoji, image []byte, filename string) (*Emo body := &bytes.Buffer{} writer := multipart.NewWriter(body) - if part, err := writer.CreateFormFile("image", filename); err != nil { + part, err := writer.CreateFormFile("image", filename) + if err != nil { return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error(), 0)} - } else if _, err = io.Copy(part, bytes.NewBuffer(image)); err != nil { + } + + if _, err := io.Copy(part, bytes.NewBuffer(image)); err != nil { return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error(), 0)} } @@ -3354,315 +3466,316 @@ func (c *Client4) CreateEmoji(emoji *Emoji, image []byte, filename string) (*Emo // GetEmojiList returns a page of custom emoji on the system. func (c *Client4) GetEmojiList(page, perPage int) ([]*Emoji, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetEmojisRoute()+query, ""); err != nil { + r, err := c.DoApiGet(c.GetEmojisRoute()+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return EmojiListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return EmojiListFromJson(r.Body), BuildResponse(r) } // GetSortedEmojiList returns a page of custom emoji on the system sorted based on the sort // parameter, blank for no sorting and "name" to sort by emoji names. func (c *Client4) GetSortedEmojiList(page, perPage int, sort string) ([]*Emoji, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v&sort=%v", page, perPage, sort) - if r, err := c.DoApiGet(c.GetEmojisRoute()+query, ""); err != nil { + r, err := c.DoApiGet(c.GetEmojisRoute()+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return EmojiListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return EmojiListFromJson(r.Body), BuildResponse(r) } // DeleteEmoji delete an custom emoji on the provided emoji id string. func (c *Client4) DeleteEmoji(emojiId string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetEmojiRoute(emojiId)); err != nil { + r, err := c.DoApiDelete(c.GetEmojiRoute(emojiId)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetEmoji returns a custom emoji based on the emojiId string. func (c *Client4) GetEmoji(emojiId string) (*Emoji, *Response) { - if r, err := c.DoApiGet(c.GetEmojiRoute(emojiId), ""); err != nil { + r, err := c.DoApiGet(c.GetEmojiRoute(emojiId), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return EmojiFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return EmojiFromJson(r.Body), BuildResponse(r) } // GetEmojiByName returns a custom emoji based on the name string. func (c *Client4) GetEmojiByName(name string) (*Emoji, *Response) { - if r, err := c.DoApiGet(c.GetEmojiByNameRoute(name), ""); err != nil { + r, err := c.DoApiGet(c.GetEmojiByNameRoute(name), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return EmojiFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return EmojiFromJson(r.Body), BuildResponse(r) } // GetEmojiImage returns the emoji image. func (c *Client4) GetEmojiImage(emojiId string) ([]byte, *Response) { - if r, err := c.DoApiGet(c.GetEmojiRoute(emojiId)+"/image", ""); err != nil { - return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - - if data, err := ioutil.ReadAll(r.Body); err != nil { - return nil, BuildErrorResponse(r, NewAppError("GetEmojiImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } else { - return data, BuildResponse(r) - } + r, apErr := c.DoApiGet(c.GetEmojiRoute(emojiId)+"/image", "") + if apErr != nil { + return nil, BuildErrorResponse(r, apErr) } + defer closeBody(r) + + data, err := ioutil.ReadAll(r.Body) + if err != nil { + return nil, BuildErrorResponse(r, NewAppError("GetEmojiImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) + } + + return data, BuildResponse(r) } // SearchEmoji returns a list of emoji matching some search criteria. func (c *Client4) SearchEmoji(search *EmojiSearch) ([]*Emoji, *Response) { - if r, err := c.DoApiPost(c.GetEmojisRoute()+"/search", search.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetEmojisRoute()+"/search", search.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return EmojiListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return EmojiListFromJson(r.Body), BuildResponse(r) } // AutocompleteEmoji returns a list of emoji starting with or matching name. func (c *Client4) AutocompleteEmoji(name string, etag string) ([]*Emoji, *Response) { query := fmt.Sprintf("?name=%v", name) - if r, err := c.DoApiGet(c.GetEmojisRoute()+"/autocomplete"+query, ""); err != nil { + r, err := c.DoApiGet(c.GetEmojisRoute()+"/autocomplete"+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return EmojiListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return EmojiListFromJson(r.Body), BuildResponse(r) } // Reaction Section // SaveReaction saves an emoji reaction for a post. Returns the saved reaction if successful, otherwise an error will be returned. func (c *Client4) SaveReaction(reaction *Reaction) (*Reaction, *Response) { - if r, err := c.DoApiPost(c.GetReactionsRoute(), reaction.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetReactionsRoute(), reaction.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ReactionFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ReactionFromJson(r.Body), BuildResponse(r) } // GetReactions returns a list of reactions to a post. func (c *Client4) GetReactions(postId string) ([]*Reaction, *Response) { - if r, err := c.DoApiGet(c.GetPostRoute(postId)+"/reactions", ""); err != nil { + r, err := c.DoApiGet(c.GetPostRoute(postId)+"/reactions", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ReactionsFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ReactionsFromJson(r.Body), BuildResponse(r) } // DeleteReaction deletes reaction of a user in a post. func (c *Client4) DeleteReaction(reaction *Reaction) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetUserRoute(reaction.UserId) + c.GetPostRoute(reaction.PostId) + fmt.Sprintf("/reactions/%v", reaction.EmojiName)); err != nil { + r, err := c.DoApiDelete(c.GetUserRoute(reaction.UserId) + c.GetPostRoute(reaction.PostId) + fmt.Sprintf("/reactions/%v", reaction.EmojiName)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // Timezone Section // GetSupportedTimezone returns a page of supported timezones on the system. func (c *Client4) GetSupportedTimezone() (SupportedTimezones, *Response) { - if r, err := c.DoApiGet(c.GetTimezonesRoute(), ""); err != nil { + r, err := c.DoApiGet(c.GetTimezonesRoute(), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TimezonesFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TimezonesFromJson(r.Body), BuildResponse(r) } // Open Graph Metadata Section -// OpenGraph return the open graph metadata for a particular url if the site have the metadata +// OpenGraph return the open graph metadata for a particular url if the site have the metadata. func (c *Client4) OpenGraph(url string) (map[string]string, *Response) { requestBody := make(map[string]string) requestBody["url"] = url - if r, err := c.DoApiPost(c.GetOpenGraphRoute(), MapToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetOpenGraphRoute(), MapToJson(requestBody)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return MapFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return MapFromJson(r.Body), BuildResponse(r) } // Jobs Section // GetJob gets a single job. func (c *Client4) GetJob(id string) (*Job, *Response) { - if r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("/%v", id), ""); err != nil { + r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("/%v", id), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return JobFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return JobFromJson(r.Body), BuildResponse(r) } -// Get all jobs, sorted with the job that was created most recently first. +// GetJobs gets all jobs, sorted with the job that was created most recently first. func (c *Client4) GetJobs(page int, perPage int) ([]*Job, *Response) { - if r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("?page=%v&per_page=%v", page, perPage), ""); err != nil { + r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("?page=%v&per_page=%v", page, perPage), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return JobsFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return JobsFromJson(r.Body), BuildResponse(r) } // GetJobsByType gets all jobs of a given type, sorted with the job that was created most recently first. func (c *Client4) GetJobsByType(jobType string, page int, perPage int) ([]*Job, *Response) { - if r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("/type/%v?page=%v&per_page=%v", jobType, page, perPage), ""); err != nil { + r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("/type/%v?page=%v&per_page=%v", jobType, page, perPage), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return JobsFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return JobsFromJson(r.Body), BuildResponse(r) } // CreateJob creates a job based on the provided job struct. func (c *Client4) CreateJob(job *Job) (*Job, *Response) { - if r, err := c.DoApiPost(c.GetJobsRoute(), job.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetJobsRoute(), job.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return JobFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return JobFromJson(r.Body), BuildResponse(r) } // CancelJob requests the cancellation of the job with the provided Id. func (c *Client4) CancelJob(jobId string) (bool, *Response) { - if r, err := c.DoApiPost(c.GetJobsRoute()+fmt.Sprintf("/%v/cancel", jobId), ""); err != nil { + r, err := c.DoApiPost(c.GetJobsRoute()+fmt.Sprintf("/%v/cancel", jobId), "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // Roles Section // GetRole gets a single role by ID. func (c *Client4) GetRole(id string) (*Role, *Response) { - if r, err := c.DoApiGet(c.GetRolesRoute()+fmt.Sprintf("/%v", id), ""); err != nil { + r, err := c.DoApiGet(c.GetRolesRoute()+fmt.Sprintf("/%v", id), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return RoleFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return RoleFromJson(r.Body), BuildResponse(r) } // GetRoleByName gets a single role by Name. func (c *Client4) GetRoleByName(name string) (*Role, *Response) { - if r, err := c.DoApiGet(c.GetRolesRoute()+fmt.Sprintf("/name/%v", name), ""); err != nil { + r, err := c.DoApiGet(c.GetRolesRoute()+fmt.Sprintf("/name/%v", name), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return RoleFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return RoleFromJson(r.Body), BuildResponse(r) } // GetRolesByNames returns a list of roles based on the provided role names. func (c *Client4) GetRolesByNames(roleNames []string) ([]*Role, *Response) { - if r, err := c.DoApiPost(c.GetRolesRoute()+"/names", ArrayToJson(roleNames)); err != nil { + r, err := c.DoApiPost(c.GetRolesRoute()+"/names", ArrayToJson(roleNames)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return RoleListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return RoleListFromJson(r.Body), BuildResponse(r) } // PatchRole partially updates a role in the system. Any missing fields are not updated. func (c *Client4) PatchRole(roleId string, patch *RolePatch) (*Role, *Response) { - if r, err := c.DoApiPut(c.GetRolesRoute()+fmt.Sprintf("/%v/patch", roleId), patch.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetRolesRoute()+fmt.Sprintf("/%v/patch", roleId), patch.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return RoleFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return RoleFromJson(r.Body), BuildResponse(r) } // Schemes Section // CreateScheme creates a new Scheme. func (c *Client4) CreateScheme(scheme *Scheme) (*Scheme, *Response) { - if r, err := c.DoApiPost(c.GetSchemesRoute(), scheme.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetSchemesRoute(), scheme.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return SchemeFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return SchemeFromJson(r.Body), BuildResponse(r) } // GetScheme gets a single scheme by ID. func (c *Client4) GetScheme(id string) (*Scheme, *Response) { - if r, err := c.DoApiGet(c.GetSchemeRoute(id), ""); err != nil { + r, err := c.DoApiGet(c.GetSchemeRoute(id), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return SchemeFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return SchemeFromJson(r.Body), BuildResponse(r) } -// Get all schemes, sorted with the most recently created first, optionally filtered by scope. +// GetSchemes gets all schemes, sorted with the most recently created first, optionally filtered by scope. func (c *Client4) GetSchemes(scope string, page int, perPage int) ([]*Scheme, *Response) { - if r, err := c.DoApiGet(c.GetSchemesRoute()+fmt.Sprintf("?scope=%v&page=%v&per_page=%v", scope, page, perPage), ""); err != nil { + r, err := c.DoApiGet(c.GetSchemesRoute()+fmt.Sprintf("?scope=%v&page=%v&per_page=%v", scope, page, perPage), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return SchemesFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return SchemesFromJson(r.Body), BuildResponse(r) } // DeleteScheme deletes a single scheme by ID. func (c *Client4) DeleteScheme(id string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetSchemeRoute(id)); err != nil { + r, err := c.DoApiDelete(c.GetSchemeRoute(id)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // PatchScheme partially updates a scheme in the system. Any missing fields are not updated. func (c *Client4) PatchScheme(id string, patch *SchemePatch) (*Scheme, *Response) { - if r, err := c.DoApiPut(c.GetSchemeRoute(id)+"/patch", patch.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetSchemeRoute(id)+"/patch", patch.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return SchemeFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return SchemeFromJson(r.Body), BuildResponse(r) } -// Get the teams using this scheme, sorted alphabetically by display name. +// GetTeamsForScheme gets the teams using this scheme, sorted alphabetically by display name. func (c *Client4) GetTeamsForScheme(schemeId string, page int, perPage int) ([]*Team, *Response) { - if r, err := c.DoApiGet(c.GetSchemeRoute(schemeId)+fmt.Sprintf("/teams?page=%v&per_page=%v", page, perPage), ""); err != nil { + r, err := c.DoApiGet(c.GetSchemeRoute(schemeId)+fmt.Sprintf("/teams?page=%v&per_page=%v", page, perPage), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamListFromJson(r.Body), BuildResponse(r) } -// Get the channels using this scheme, sorted alphabetically by display name. +// GetChannelsForScheme gets the channels using this scheme, sorted alphabetically by display name. func (c *Client4) GetChannelsForScheme(schemeId string, page int, perPage int) (ChannelList, *Response) { - if r, err := c.DoApiGet(c.GetSchemeRoute(schemeId)+fmt.Sprintf("/channels?page=%v&per_page=%v", page, perPage), ""); err != nil { + r, err := c.DoApiGet(c.GetSchemeRoute(schemeId)+fmt.Sprintf("/channels?page=%v&per_page=%v", page, perPage), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return *ChannelListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return *ChannelListFromJson(r.Body), BuildResponse(r) } // Plugin Section @@ -3673,13 +3786,16 @@ func (c *Client4) UploadPlugin(file io.Reader) (*Manifest, *Response) { body := new(bytes.Buffer) writer := multipart.NewWriter(body) - if part, err := writer.CreateFormFile("plugin", "plugin.tar.gz"); err != nil { - return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)} - } else if _, err = io.Copy(part, file); err != nil { + part, err := writer.CreateFormFile("plugin", "plugin.tar.gz") + if err != nil { return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)} } - if err := writer.Close(); err != nil { + if _, err = io.Copy(part, file); err != nil { + return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)} + } + + if err = writer.Close(); err != nil { return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)} } @@ -3690,150 +3806,161 @@ func (c *Client4) UploadPlugin(file io.Reader) (*Manifest, *Response) { rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } - if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil { + rp, err := c.HttpClient.Do(rq) + if err != nil || rp == nil { return nil, BuildErrorResponse(rp, NewAppError("UploadPlugin", "model.client.connecting.app_error", nil, err.Error(), 0)) - } else { - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } else { - return ManifestFromJson(rp.Body), BuildResponse(rp) - } } + defer closeBody(rp) + + if rp.StatusCode >= 300 { + return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) + } + + return ManifestFromJson(rp.Body), BuildResponse(rp) } // GetPlugins will return a list of plugin manifests for currently active plugins. // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE. func (c *Client4) GetPlugins() (*PluginsResponse, *Response) { - if r, err := c.DoApiGet(c.GetPluginsRoute(), ""); err != nil { + r, err := c.DoApiGet(c.GetPluginsRoute(), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PluginsResponseFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PluginsResponseFromJson(r.Body), BuildResponse(r) } // GetPluginStatuses will return the plugins installed on any server in the cluster, for reporting // to the administrator via the system console. // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE. func (c *Client4) GetPluginStatuses() (PluginStatuses, *Response) { - if r, err := c.DoApiGet(c.GetPluginsRoute(), "/statuses"); err != nil { + r, err := c.DoApiGet(c.GetPluginsRoute(), "/statuses") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PluginStatusesFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PluginStatusesFromJson(r.Body), BuildResponse(r) } -// RemovePlugin will deactivate and delete a plugin. +// RemovePlugin will disable and delete a plugin. // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE. func (c *Client4) RemovePlugin(id string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetPluginRoute(id)); err != nil { + r, err := c.DoApiDelete(c.GetPluginRoute(id)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetWebappPlugins will return a list of plugins that the webapp should download. // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE. func (c *Client4) GetWebappPlugins() ([]*Manifest, *Response) { - if r, err := c.DoApiGet(c.GetPluginsRoute()+"/webapp", ""); err != nil { + r, err := c.DoApiGet(c.GetPluginsRoute()+"/webapp", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ManifestListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ManifestListFromJson(r.Body), BuildResponse(r) } -// ActivatePlugin will activate an plugin installed. +// EnablePlugin will enable an plugin installed. // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE. func (c *Client4) EnablePlugin(id string) (bool, *Response) { - if r, err := c.DoApiPost(c.GetPluginRoute(id)+"/enable", ""); err != nil { + r, err := c.DoApiPost(c.GetPluginRoute(id)+"/enable", "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } -// DeactivatePlugin will deactivate an active plugin. +// DisablePlugin will disable an enabled plugin. // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE. func (c *Client4) DisablePlugin(id string) (bool, *Response) { - if r, err := c.DoApiPost(c.GetPluginRoute(id)+"/disable", ""); err != nil { + r, err := c.DoApiPost(c.GetPluginRoute(id)+"/disable", "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // UpdateChannelScheme will update a channel's scheme. func (c *Client4) UpdateChannelScheme(channelId, schemeId string) (bool, *Response) { sip := &SchemeIDPatch{SchemeID: &schemeId} - if r, err := c.DoApiPut(c.GetChannelSchemeRoute(channelId), sip.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetChannelSchemeRoute(channelId), sip.ToJson()) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // UpdateTeamScheme will update a team's scheme. func (c *Client4) UpdateTeamScheme(teamId, schemeId string) (bool, *Response) { sip := &SchemeIDPatch{SchemeID: &schemeId} - if r, err := c.DoApiPut(c.GetTeamSchemeRoute(teamId), sip.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetTeamSchemeRoute(teamId), sip.ToJson()) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetRedirectLocation retrieves the value of the 'Location' header of an HTTP response for a given URL. func (c *Client4) GetRedirectLocation(urlParam, etag string) (string, *Response) { url := fmt.Sprintf("%s?url=%s", c.GetRedirectLocationRoute(), url.QueryEscape(urlParam)) - if r, err := c.DoApiGet(url, etag); err != nil { + r, err := c.DoApiGet(url, etag) + if err != nil { return "", BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return MapFromJson(r.Body)["location"], BuildResponse(r) } + defer closeBody(r) + return MapFromJson(r.Body)["location"], BuildResponse(r) } -func (c *Client4) RegisteTermsOfServiceAction(userId, termsOfServiceId string, accepted bool) (*bool, *Response) { - url := c.GetRegisterTermsOfServiceRoute(userId) +// RegisterTermsOfServiceAction saves action performed by a user against a specific terms of service. +func (c *Client4) RegisterTermsOfServiceAction(userId, termsOfServiceId string, accepted bool) (*bool, *Response) { + url := c.GetUserTermsOfServiceRoute(userId) data := map[string]interface{}{"termsOfServiceId": termsOfServiceId, "accepted": accepted} - - if r, err := c.DoApiPost(url, StringInterfaceToJson(data)); err != nil { + r, err := c.DoApiPost(url, StringInterfaceToJson(data)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return NewBool(CheckStatusOK(r)), BuildResponse(r) } + defer closeBody(r) + return NewBool(CheckStatusOK(r)), BuildResponse(r) } +// GetTermsOfService fetches the latest terms of service func (c *Client4) GetTermsOfService(etag string) (*TermsOfService, *Response) { url := c.GetTermsOfServiceRoute() - - if r, err := c.DoApiGet(url, etag); err != nil { + r, err := c.DoApiGet(url, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TermsOfServiceFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TermsOfServiceFromJson(r.Body), BuildResponse(r) } +// GetUserTermsOfService fetches user's latest terms of service action if the latest action was for acceptance. +func (c *Client4) GetUserTermsOfService(userId, etag string) (*UserTermsOfService, *Response) { + url := c.GetUserTermsOfServiceRoute(userId) + r, err := c.DoApiGet(url, etag) + if err != nil { + return nil, BuildErrorResponse(r, err) + } + defer closeBody(r) + return UserTermsOfServiceFromJson(r.Body), BuildResponse(r) +} + +// CreateTermsOfService creates new terms of service. func (c *Client4) CreateTermsOfService(text, userId string) (*TermsOfService, *Response) { url := c.GetTermsOfServiceRoute() - - data := map[string]string{"text": text} - if r, err := c.DoApiPost(url, MapToJson(data)); err != nil { + data := map[string]interface{}{"text": text} + r, err := c.DoApiPost(url, StringInterfaceToJson(data)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TermsOfServiceFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TermsOfServiceFromJson(r.Body), BuildResponse(r) } diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/command_args.go b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/command_args.go index 4a635a1..a3d4efa 100644 --- a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/command_args.go +++ b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/command_args.go @@ -16,6 +16,7 @@ type CommandArgs struct { TeamId string `json:"team_id"` RootId string `json:"root_id"` ParentId string `json:"parent_id"` + TriggerId string `json:"trigger_id,omitempty"` Command string `json:"command"` SiteURL string `json:"-"` T goi18n.TranslateFunc `json:"-"` diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/command_response.go b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/command_response.go index 1ed5286..2f6cd0d 100644 --- a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/command_response.go +++ b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/command_response.go @@ -18,14 +18,16 @@ const ( ) type CommandResponse struct { - ResponseType string `json:"response_type"` - Text string `json:"text"` - Username string `json:"username"` - IconURL string `json:"icon_url"` - Type string `json:"type"` - Props StringInterface `json:"props"` - GotoLocation string `json:"goto_location"` - Attachments []*SlackAttachment `json:"attachments"` + ResponseType string `json:"response_type"` + Text string `json:"text"` + Username string `json:"username"` + IconURL string `json:"icon_url"` + Type string `json:"type"` + Props StringInterface `json:"props"` + GotoLocation string `json:"goto_location"` + TriggerId string `json:"trigger_id"` + Attachments []*SlackAttachment `json:"attachments"` + ExtraResponses []*CommandResponse `json:"extra_responses"` } func (o *CommandResponse) ToJson() string { @@ -63,5 +65,11 @@ func CommandResponseFromJson(data io.Reader) (*CommandResponse, error) { o.Attachments = StringifySlackFieldValue(o.Attachments) + if o.ExtraResponses != nil { + for _, resp := range o.ExtraResponses { + resp.Attachments = StringifySlackFieldValue(resp.Attachments) + } + } + return &o, nil } diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/config.go b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/config.go index d59b8d6..c7ce669 100644 --- a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/config.go +++ b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/config.go @@ -4,12 +4,14 @@ package model import ( + "crypto/tls" "encoding/json" "io" "math" "net" "net/http" "net/url" + "os" "regexp" "strconv" "strings" @@ -110,6 +112,7 @@ const ( SUPPORT_SETTINGS_DEFAULT_HELP_LINK = "https://about.mattermost.com/default-help/" SUPPORT_SETTINGS_DEFAULT_REPORT_A_PROBLEM_LINK = "https://about.mattermost.com/default-report-a-problem/" SUPPORT_SETTINGS_DEFAULT_SUPPORT_EMAIL = "feedback@mattermost.com" + SUPPORT_SETTINGS_DEFAULT_RE_ACCEPTANCE_PERIOD = 365 LDAP_SETTINGS_DEFAULT_FIRST_NAME_ATTRIBUTE = "" LDAP_SETTINGS_DEFAULT_LAST_NAME_ATTRIBUTE = "" @@ -133,9 +136,6 @@ const ( NATIVEAPP_SETTINGS_DEFAULT_ANDROID_APP_DOWNLOAD_LINK = "https://about.mattermost.com/mattermost-android-app/" NATIVEAPP_SETTINGS_DEFAULT_IOS_APP_DOWNLOAD_LINK = "https://about.mattermost.com/mattermost-ios-app/" - WEBRTC_SETTINGS_DEFAULT_STUN_URI = "" - WEBRTC_SETTINGS_DEFAULT_TURN_URI = "" - ANALYTICS_SETTINGS_DEFAULT_MAX_USERS_FOR_STATISTICS = 2500 ANNOUNCEMENT_SETTINGS_DEFAULT_BANNER_COLOR = "#f2a93b" @@ -174,6 +174,31 @@ const ( CLIENT_SIDE_CERT_CHECK_SECONDARY_AUTH = "secondary" ) +var ServerTLSSupportedCiphers = map[string]uint16{ + "TLS_RSA_WITH_RC4_128_SHA": tls.TLS_RSA_WITH_RC4_128_SHA, + "TLS_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA, + "TLS_RSA_WITH_AES_128_CBC_SHA": tls.TLS_RSA_WITH_AES_128_CBC_SHA, + "TLS_RSA_WITH_AES_256_CBC_SHA": tls.TLS_RSA_WITH_AES_256_CBC_SHA, + "TLS_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_RSA_WITH_AES_128_CBC_SHA256, + "TLS_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_RSA_WITH_AES_128_GCM_SHA256, + "TLS_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_RSA_WITH_AES_256_GCM_SHA384, + "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + "TLS_ECDHE_RSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA, + "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, +} + type ServiceSettings struct { SiteURL *string WebsocketURL *string @@ -182,6 +207,10 @@ type ServiceSettings struct { ConnectionSecurity *string TLSCertFile *string TLSKeyFile *string + TLSMinVer *string + TLSStrictTransport *bool + TLSStrictTransportMaxAge *int64 + TLSOverwriteCiphers []string UseLetsEncrypt *bool LetsEncryptCertificateCacheFile *string Forward80To443 *bool @@ -194,7 +223,7 @@ type ServiceSettings struct { EnableIncomingWebhooks bool EnableOutgoingWebhooks bool EnableCommands *bool - EnableOnlyAdminIntegrations *bool + DEPRECATED_DO_NOT_USE_EnableOnlyAdminIntegrations *bool `json:"EnableOnlyAdminIntegrations"` // This field is deprecated and must not be used. EnablePostUsernameOverride bool EnablePostIconOverride bool EnableLinkPreviews *bool @@ -224,9 +253,9 @@ type ServiceSettings struct { EnableGifPicker *bool GfycatApiKey *string GfycatApiSecret *string - RestrictCustomEmojiCreation *string - RestrictPostDelete *string - AllowEditPost *string + DEPRECATED_DO_NOT_USE_RestrictCustomEmojiCreation *string `json:"RestrictCustomEmojiCreation"` // This field is deprecated and must not be used. + DEPRECATED_DO_NOT_USE_RestrictPostDelete *string `json:"RestrictPostDelete"` // This field is deprecated and must not be used. + DEPRECATED_DO_NOT_USE_AllowEditPost *string `json:"AllowEditPost"` // This field is deprecated and must not be used. PostEditTimeLimit *int TimeBetweenUserTypingUpdatesMilliseconds *int64 EnablePostSearch *bool @@ -246,7 +275,6 @@ type ServiceSettings struct { ImageProxyOptions *string EnableAPITeamDeletion *bool ExperimentalEnableHardenedMode *bool - ExperimentalLimitClientConfig *bool EnableEmailInvitations *bool } @@ -324,6 +352,22 @@ func (s *ServiceSettings) SetDefaults() { s.TLSCertFile = NewString(SERVICE_SETTINGS_DEFAULT_TLS_CERT_FILE) } + if s.TLSMinVer == nil { + s.TLSMinVer = NewString("1.2") + } + + if s.TLSStrictTransport == nil { + s.TLSStrictTransport = NewBool(false) + } + + if s.TLSStrictTransportMaxAge == nil { + s.TLSStrictTransportMaxAge = NewInt64(63072000) + } + + if s.TLSOverwriteCiphers == nil { + s.TLSOverwriteCiphers = []string{} + } + if s.UseLetsEncrypt == nil { s.UseLetsEncrypt = NewBool(false) } @@ -404,8 +448,8 @@ func (s *ServiceSettings) SetDefaults() { s.EnableCommands = NewBool(false) } - if s.EnableOnlyAdminIntegrations == nil { - s.EnableOnlyAdminIntegrations = NewBool(true) + if s.DEPRECATED_DO_NOT_USE_EnableOnlyAdminIntegrations == nil { + s.DEPRECATED_DO_NOT_USE_EnableOnlyAdminIntegrations = NewBool(true) } if s.WebsocketPort == nil { @@ -462,16 +506,16 @@ func (s *ServiceSettings) SetDefaults() { s.GfycatApiSecret = NewString(SERVICE_SETTINGS_DEFAULT_GFYCAT_API_SECRET) } - if s.RestrictCustomEmojiCreation == nil { - s.RestrictCustomEmojiCreation = NewString(RESTRICT_EMOJI_CREATION_ALL) + if s.DEPRECATED_DO_NOT_USE_RestrictCustomEmojiCreation == nil { + s.DEPRECATED_DO_NOT_USE_RestrictCustomEmojiCreation = NewString(RESTRICT_EMOJI_CREATION_ALL) } - if s.RestrictPostDelete == nil { - s.RestrictPostDelete = NewString(PERMISSIONS_DELETE_POST_ALL) + if s.DEPRECATED_DO_NOT_USE_RestrictPostDelete == nil { + s.DEPRECATED_DO_NOT_USE_RestrictPostDelete = NewString(PERMISSIONS_DELETE_POST_ALL) } - if s.AllowEditPost == nil { - s.AllowEditPost = NewString(ALLOW_EDIT_POST_ALWAYS) + if s.DEPRECATED_DO_NOT_USE_AllowEditPost == nil { + s.DEPRECATED_DO_NOT_USE_AllowEditPost = NewString(ALLOW_EDIT_POST_ALWAYS) } if s.ExperimentalEnableAuthenticationTransfer == nil { @@ -522,10 +566,6 @@ func (s *ServiceSettings) SetDefaults() { if s.ExperimentalEnableHardenedMode == nil { s.ExperimentalEnableHardenedMode = NewBool(false) } - - if s.ExperimentalLimitClientConfig == nil { - s.ExperimentalLimitClientConfig = NewBool(false) - } } type ClusterSettings struct { @@ -611,6 +651,7 @@ func (s *MetricsSettings) SetDefaults() { type ExperimentalSettings struct { ClientSideCertEnable *bool ClientSideCertCheck *string + EnablePostMetadata *bool } func (s *ExperimentalSettings) SetDefaults() { @@ -621,6 +662,10 @@ func (s *ExperimentalSettings) SetDefaults() { if s.ClientSideCertCheck == nil { s.ClientSideCertCheck = NewString(CLIENT_SIDE_CERT_CHECK_SECONDARY_AUTH) } + + if s.EnablePostMetadata == nil { + s.EnablePostMetadata = NewBool(false) + } } type AnalyticsSettings struct { @@ -644,17 +689,16 @@ type SSOSettings struct { } type SqlSettings struct { - DriverName *string - DataSource *string - DataSourceReplicas []string - DataSourceSearchReplicas []string - MaxIdleConns *int - ConnMaxLifetimeMilliseconds *int - MaxOpenConns *int - Trace bool - AtRestEncryptKey string - QueryTimeout *int - EnablePublicChannelsMaterialization *bool + DriverName *string + DataSource *string + DataSourceReplicas []string + DataSourceSearchReplicas []string + MaxIdleConns *int + ConnMaxLifetimeMilliseconds *int + MaxOpenConns *int + Trace bool + AtRestEncryptKey string + QueryTimeout *int } func (s *SqlSettings) SetDefaults() { @@ -685,10 +729,6 @@ func (s *SqlSettings) SetDefaults() { if s.QueryTimeout == nil { s.QueryTimeout = NewInt(30) } - - if s.EnablePublicChannelsMaterialization == nil { - s.EnablePublicChannelsMaterialization = NewBool(true) - } } type LogSettings struct { @@ -996,13 +1036,14 @@ type PrivacySettings struct { } type SupportSettings struct { - TermsOfServiceLink *string - PrivacyPolicyLink *string - AboutLink *string - HelpLink *string - ReportAProblemLink *string - SupportEmail *string - CustomTermsOfServiceEnabled *bool + TermsOfServiceLink *string + PrivacyPolicyLink *string + AboutLink *string + HelpLink *string + ReportAProblemLink *string + SupportEmail *string + CustomTermsOfServiceEnabled *bool + CustomTermsOfServiceReAcceptancePeriod *int } func (s *SupportSettings) SetDefaults() { @@ -1053,6 +1094,10 @@ func (s *SupportSettings) SetDefaults() { if s.CustomTermsOfServiceEnabled == nil { s.CustomTermsOfServiceEnabled = NewBool(false) } + + if s.CustomTermsOfServiceReAcceptancePeriod == nil { + s.CustomTermsOfServiceReAcceptancePeriod = NewInt(SUPPORT_SETTINGS_DEFAULT_RE_ACCEPTANCE_PERIOD) + } } type AnnouncementSettings struct { @@ -1111,37 +1156,37 @@ func (s *ThemeSettings) SetDefaults() { } type TeamSettings struct { - SiteName string - MaxUsersPerTeam *int - EnableTeamCreation *bool - EnableUserCreation *bool - EnableOpenServer *bool - EnableUserDeactivation *bool - RestrictCreationToDomains string - EnableCustomBrand *bool - CustomBrandText *string - CustomDescriptionText *string - RestrictDirectMessage *string - RestrictTeamInvite *string - RestrictPublicChannelManagement *string - RestrictPrivateChannelManagement *string - RestrictPublicChannelCreation *string - RestrictPrivateChannelCreation *string - RestrictPublicChannelDeletion *string - RestrictPrivateChannelDeletion *string - RestrictPrivateChannelManageMembers *string - EnableXToLeaveChannelsFromLHS *bool - UserStatusAwayTimeout *int64 - MaxChannelsPerTeam *int64 - MaxNotificationsPerChannel *int64 - EnableConfirmNotificationsToChannel *bool - TeammateNameDisplay *string - ExperimentalViewArchivedChannels *bool - ExperimentalEnableAutomaticReplies *bool - ExperimentalHideTownSquareinLHS *bool - ExperimentalTownSquareIsReadOnly *bool - ExperimentalPrimaryTeam *string - ExperimentalDefaultChannels []string + SiteName string + MaxUsersPerTeam *int + DEPRECATED_DO_NOT_USE_EnableTeamCreation *bool `json:"EnableTeamCreation"` // This field is deprecated and must not be used. + EnableUserCreation *bool + EnableOpenServer *bool + EnableUserDeactivation *bool + RestrictCreationToDomains string + EnableCustomBrand *bool + CustomBrandText *string + CustomDescriptionText *string + RestrictDirectMessage *string + DEPRECATED_DO_NOT_USE_RestrictTeamInvite *string `json:"RestrictTeamInvite"` // This field is deprecated and must not be used. + DEPRECATED_DO_NOT_USE_RestrictPublicChannelManagement *string `json:"RestrictPublicChannelManagement"` // This field is deprecated and must not be used. + DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManagement *string `json:"RestrictPrivateChannelManagement"` // This field is deprecated and must not be used. + DEPRECATED_DO_NOT_USE_RestrictPublicChannelCreation *string `json:"RestrictPublicChannelCreation"` // This field is deprecated and must not be used. + DEPRECATED_DO_NOT_USE_RestrictPrivateChannelCreation *string `json:"RestrictPrivateChannelCreation"` // This field is deprecated and must not be used. + DEPRECATED_DO_NOT_USE_RestrictPublicChannelDeletion *string `json:"RestrictPublicChannelDeletion"` // This field is deprecated and must not be used. + DEPRECATED_DO_NOT_USE_RestrictPrivateChannelDeletion *string `json:"RestrictPrivateChannelDeletion"` // This field is deprecated and must not be used. + DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManageMembers *string `json:"RestrictPrivateChannelManageMembers"` // This field is deprecated and must not be used. + EnableXToLeaveChannelsFromLHS *bool + UserStatusAwayTimeout *int64 + MaxChannelsPerTeam *int64 + MaxNotificationsPerChannel *int64 + EnableConfirmNotificationsToChannel *bool + TeammateNameDisplay *string + ExperimentalViewArchivedChannels *bool + ExperimentalEnableAutomaticReplies *bool + ExperimentalHideTownSquareinLHS *bool + ExperimentalTownSquareIsReadOnly *bool + ExperimentalPrimaryTeam *string + ExperimentalDefaultChannels []string } func (s *TeamSettings) SetDefaults() { @@ -1173,49 +1218,49 @@ func (s *TeamSettings) SetDefaults() { s.RestrictDirectMessage = NewString(DIRECT_MESSAGE_ANY) } - if s.RestrictTeamInvite == nil { - s.RestrictTeamInvite = NewString(PERMISSIONS_ALL) + if s.DEPRECATED_DO_NOT_USE_RestrictTeamInvite == nil { + s.DEPRECATED_DO_NOT_USE_RestrictTeamInvite = NewString(PERMISSIONS_ALL) } - if s.RestrictPublicChannelManagement == nil { - s.RestrictPublicChannelManagement = NewString(PERMISSIONS_ALL) + if s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelManagement == nil { + s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelManagement = NewString(PERMISSIONS_ALL) } - if s.RestrictPrivateChannelManagement == nil { - s.RestrictPrivateChannelManagement = NewString(PERMISSIONS_ALL) + if s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManagement == nil { + s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManagement = NewString(PERMISSIONS_ALL) } - if s.RestrictPublicChannelCreation == nil { - s.RestrictPublicChannelCreation = new(string) + if s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelCreation == nil { + s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelCreation = new(string) // If this setting does not exist, assume migration from <3.6, so use management setting as default. - if *s.RestrictPublicChannelManagement == PERMISSIONS_CHANNEL_ADMIN { - *s.RestrictPublicChannelCreation = PERMISSIONS_TEAM_ADMIN + if *s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelManagement == PERMISSIONS_CHANNEL_ADMIN { + *s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelCreation = PERMISSIONS_TEAM_ADMIN } else { - *s.RestrictPublicChannelCreation = *s.RestrictPublicChannelManagement + *s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelCreation = *s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelManagement } } - if s.RestrictPrivateChannelCreation == nil { + if s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelCreation == nil { // If this setting does not exist, assume migration from <3.6, so use management setting as default. - if *s.RestrictPrivateChannelManagement == PERMISSIONS_CHANNEL_ADMIN { - s.RestrictPrivateChannelCreation = NewString(PERMISSIONS_TEAM_ADMIN) + if *s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManagement == PERMISSIONS_CHANNEL_ADMIN { + s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelCreation = NewString(PERMISSIONS_TEAM_ADMIN) } else { - s.RestrictPrivateChannelCreation = NewString(*s.RestrictPrivateChannelManagement) + s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelCreation = NewString(*s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManagement) } } - if s.RestrictPublicChannelDeletion == nil { + if s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelDeletion == nil { // If this setting does not exist, assume migration from <3.6, so use management setting as default. - s.RestrictPublicChannelDeletion = NewString(*s.RestrictPublicChannelManagement) + s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelDeletion = NewString(*s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelManagement) } - if s.RestrictPrivateChannelDeletion == nil { + if s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelDeletion == nil { // If this setting does not exist, assume migration from <3.6, so use management setting as default. - s.RestrictPrivateChannelDeletion = NewString(*s.RestrictPrivateChannelManagement) + s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelDeletion = NewString(*s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManagement) } - if s.RestrictPrivateChannelManageMembers == nil { - s.RestrictPrivateChannelManageMembers = NewString(PERMISSIONS_ALL) + if s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManageMembers == nil { + s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManageMembers = NewString(PERMISSIONS_ALL) } if s.EnableXToLeaveChannelsFromLHS == nil { @@ -1258,8 +1303,8 @@ func (s *TeamSettings) SetDefaults() { s.ExperimentalDefaultChannels = []string{} } - if s.EnableTeamCreation == nil { - s.EnableTeamCreation = NewBool(true) + if s.DEPRECATED_DO_NOT_USE_EnableTeamCreation == nil { + s.DEPRECATED_DO_NOT_USE_EnableTeamCreation = NewBool(true) } if s.EnableUserCreation == nil { @@ -1624,51 +1669,6 @@ func (s *NativeAppSettings) SetDefaults() { } } -type WebrtcSettings struct { - Enable *bool - GatewayWebsocketUrl *string - GatewayAdminUrl *string - GatewayAdminSecret *string - StunURI *string - TurnURI *string - TurnUsername *string - TurnSharedKey *string -} - -func (s *WebrtcSettings) SetDefaults() { - if s.Enable == nil { - s.Enable = NewBool(false) - } - - if s.GatewayWebsocketUrl == nil { - s.GatewayWebsocketUrl = NewString("") - } - - if s.GatewayAdminUrl == nil { - s.GatewayAdminUrl = NewString("") - } - - if s.GatewayAdminSecret == nil { - s.GatewayAdminSecret = NewString("") - } - - if s.StunURI == nil { - s.StunURI = NewString(WEBRTC_SETTINGS_DEFAULT_STUN_URI) - } - - if s.TurnURI == nil { - s.TurnURI = NewString(WEBRTC_SETTINGS_DEFAULT_TURN_URI) - } - - if s.TurnUsername == nil { - s.TurnUsername = NewString("") - } - - if s.TurnSharedKey == nil { - s.TurnSharedKey = NewString("") - } -} - type ElasticsearchSettings struct { ConnectionUrl *string Username *string @@ -1886,14 +1886,6 @@ func (s *MessageExportSettings) SetDefaults() { s.ExportFromTimestamp = NewInt64(0) } - if s.EnableExport != nil && *s.EnableExport && *s.ExportFromTimestamp == int64(0) { - // when the feature is enabled via the System Console, use the current timestamp as the start time for future exports - s.ExportFromTimestamp = NewInt64(GetMillis()) - } else if s.EnableExport != nil && !*s.EnableExport { - // when the feature is disabled, reset the timestamp so that the timestamp will be set if the feature is re-enabled - s.ExportFromTimestamp = NewInt64(0) - } - if s.BatchSize == nil { s.BatchSize = NewInt(10000) } @@ -1959,7 +1951,6 @@ type Config struct { MetricsSettings MetricsSettings ExperimentalSettings ExperimentalSettings AnalyticsSettings AnalyticsSettings - WebrtcSettings WebrtcSettings ElasticsearchSettings ElasticsearchSettings DataRetentionSettings DataRetentionSettings MessageExportSettings MessageExportSettings @@ -2035,7 +2026,6 @@ func (o *Config) SetDefaults() { o.RateLimitSettings.SetDefaults() o.LogSettings.SetDefaults() o.JobSettings.SetDefaults() - o.WebrtcSettings.SetDefaults() o.MessageExportSettings.SetDefaults() o.TimezoneSettings.SetDefaults() o.DisplaySettings.SetDefaults() @@ -2087,10 +2077,6 @@ func (o *Config) IsValid() *AppError { return err } - if err := o.WebrtcSettings.isValid(); err != nil { - return err - } - if err := o.ServiceSettings.isValid(); err != nil { return err } @@ -2322,36 +2308,37 @@ func (ss *SamlSettings) isValid() *AppError { return nil } -func (ws *WebrtcSettings) isValid() *AppError { - if *ws.Enable { - if len(*ws.GatewayWebsocketUrl) == 0 || !IsValidWebsocketUrl(*ws.GatewayWebsocketUrl) { - return NewAppError("Config.IsValid", "model.config.is_valid.webrtc_gateway_ws_url.app_error", nil, "", http.StatusBadRequest) - } else if len(*ws.GatewayAdminUrl) == 0 || !IsValidHttpUrl(*ws.GatewayAdminUrl) { - return NewAppError("Config.IsValid", "model.config.is_valid.webrtc_gateway_admin_url.app_error", nil, "", http.StatusBadRequest) - } else if len(*ws.GatewayAdminSecret) == 0 { - return NewAppError("Config.IsValid", "model.config.is_valid.webrtc_gateway_admin_secret.app_error", nil, "", http.StatusBadRequest) - } else if len(*ws.StunURI) != 0 && !IsValidTurnOrStunServer(*ws.StunURI) { - return NewAppError("Config.IsValid", "model.config.is_valid.webrtc_stun_uri.app_error", nil, "", http.StatusBadRequest) - } else if len(*ws.TurnURI) != 0 { - if !IsValidTurnOrStunServer(*ws.TurnURI) { - return NewAppError("Config.IsValid", "model.config.is_valid.webrtc_turn_uri.app_error", nil, "", http.StatusBadRequest) - } - if len(*ws.TurnUsername) == 0 { - return NewAppError("Config.IsValid", "model.config.is_valid.webrtc_turn_username.app_error", nil, "", http.StatusBadRequest) - } else if len(*ws.TurnSharedKey) == 0 { - return NewAppError("Config.IsValid", "model.config.is_valid.webrtc_turn_shared_key.app_error", nil, "", http.StatusBadRequest) - } - } - } - - return nil -} - func (ss *ServiceSettings) isValid() *AppError { if !(*ss.ConnectionSecurity == CONN_SECURITY_NONE || *ss.ConnectionSecurity == CONN_SECURITY_TLS) { return NewAppError("Config.IsValid", "model.config.is_valid.webserver_security.app_error", nil, "", http.StatusBadRequest) } + if *ss.ConnectionSecurity == CONN_SECURITY_TLS && *ss.UseLetsEncrypt == false { + appErr := NewAppError("Config.IsValid", "model.config.is_valid.tls_cert_file.app_error", nil, "", http.StatusBadRequest) + + if *ss.TLSCertFile == "" { + return appErr + } else if _, err := os.Stat(*ss.TLSCertFile); os.IsNotExist(err) { + return appErr + } + + appErr = NewAppError("Config.IsValid", "model.config.is_valid.tls_key_file.app_error", nil, "", http.StatusBadRequest) + + if *ss.TLSKeyFile == "" { + return appErr + } else if _, err := os.Stat(*ss.TLSKeyFile); os.IsNotExist(err) { + return appErr + } + } + + if len(ss.TLSOverwriteCiphers) > 0 { + for _, cipher := range ss.TLSOverwriteCiphers { + if _, ok := ServerTLSSupportedCiphers[cipher]; !ok { + return NewAppError("Config.IsValid", "model.config.is_valid.tls_overwrite_cipher.app_error", map[string]interface{}{"name": cipher}, "", http.StatusBadRequest) + } + } + } + if *ss.ReadTimeout <= 0 { return NewAppError("Config.IsValid", "model.config.is_valid.read_timeout.app_error", nil, "", http.StatusBadRequest) } diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/emoji.go b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/emoji.go index f14af89..afe6149 100644 --- a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/emoji.go +++ b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/emoji.go @@ -7,6 +7,7 @@ import ( "encoding/json" "io" "net/http" + "regexp" ) const ( @@ -14,6 +15,8 @@ const ( EMOJI_SORT_BY_NAME = "name" ) +var EMOJI_PATTERN = regexp.MustCompile(`:[a-zA-Z0-9_-]+:`) + type Emoji struct { Id string `json:"id"` CreateAt int64 `json:"create_at"` diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/file_info.go b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/file_info.go index e0bbfcf..7a3e54a 100644 --- a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/file_info.go +++ b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/file_info.go @@ -85,7 +85,7 @@ func (o *FileInfo) IsValid() *AppError { return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.id.app_error", nil, "", http.StatusBadRequest) } - if len(o.CreatorId) != 26 { + if len(o.CreatorId) != 26 && o.CreatorId != "nouser" { return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.user_id.app_error", nil, "id="+o.Id, http.StatusBadRequest) } diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/integration_action.go b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/integration_action.go new file mode 100644 index 0000000..7ea928c --- /dev/null +++ b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/integration_action.go @@ -0,0 +1,294 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package model + +import ( + "crypto" + "crypto/ecdsa" + "crypto/rand" + "encoding/asn1" + "encoding/base64" + "encoding/json" + "io" + "math/big" + "net/http" + "strconv" + "strings" +) + +const ( + POST_ACTION_TYPE_BUTTON = "button" + POST_ACTION_TYPE_SELECT = "select" + INTERACTIVE_DIALOG_TRIGGER_TIMEOUT_MILLISECONDS = 3000 +) + +type DoPostActionRequest struct { + SelectedOption string `json:"selected_option"` +} + +type PostAction struct { + Id string `json:"id"` + Name string `json:"name"` + Type string `json:"type"` + DataSource string `json:"data_source"` + Options []*PostActionOptions `json:"options"` + Integration *PostActionIntegration `json:"integration,omitempty"` +} + +type PostActionOptions struct { + Text string `json:"text"` + Value string `json:"value"` +} + +type PostActionIntegration struct { + URL string `json:"url,omitempty"` + Context map[string]interface{} `json:"context,omitempty"` +} + +type PostActionIntegrationRequest struct { + UserId string `json:"user_id"` + ChannelId string `json:"channel_id"` + TeamId string `json:"team_id"` + PostId string `json:"post_id"` + TriggerId string `json:"trigger_id"` + Type string `json:"type"` + DataSource string `json:"data_source"` + Context map[string]interface{} `json:"context,omitempty"` +} + +type PostActionIntegrationResponse struct { + Update *Post `json:"update"` + EphemeralText string `json:"ephemeral_text"` +} + +type PostActionAPIResponse struct { + Status string `json:"status"` // needed to maintain backwards compatibility + TriggerId string `json:"trigger_id"` +} + +type Dialog struct { + CallbackId string `json:"callback_id"` + Title string `json:"title"` + IconURL string `json:"icon_url"` + Elements []DialogElement `json:"elements"` + SubmitLabel string `json:"submit_label"` + NotifyOnCancel bool `json:"notify_on_cancel"` + State string `json:"state"` +} + +type DialogElement struct { + DisplayName string `json:"display_name"` + Name string `json:"name"` + Type string `json:"type"` + SubType string `json:"subtype"` + Default string `json:"default"` + Placeholder string `json:"placeholder"` + HelpText string `json:"help_text"` + Optional bool `json:"optional"` + MinLength int `json:"min_length"` + MaxLength int `json:"max_length"` + DataSource string `json:"data_source"` + Options []*PostActionOptions `json:"options"` +} + +type OpenDialogRequest struct { + TriggerId string `json:"trigger_id"` + URL string `json:"url"` + Dialog Dialog `json:"dialog"` +} + +type SubmitDialogRequest struct { + Type string `json:"type"` + URL string `json:"url,omitempty"` + CallbackId string `json:"callback_id"` + State string `json:"state"` + UserId string `json:"user_id"` + ChannelId string `json:"channel_id"` + TeamId string `json:"team_id"` + Submission map[string]interface{} `json:"submission"` + Cancelled bool `json:"cancelled"` +} + +type SubmitDialogResponse struct { + Errors map[string]string `json:"errors,omitempty"` +} + +func GenerateTriggerId(userId string, s crypto.Signer) (string, string, *AppError) { + clientTriggerId := NewId() + triggerData := strings.Join([]string{clientTriggerId, userId, strconv.FormatInt(GetMillis(), 10)}, ":") + ":" + + h := crypto.SHA256 + sum := h.New() + sum.Write([]byte(triggerData)) + signature, err := s.Sign(rand.Reader, sum.Sum(nil), h) + if err != nil { + return "", "", NewAppError("GenerateTriggerId", "interactive_message.generate_trigger_id.signing_failed", nil, err.Error(), http.StatusInternalServerError) + } + + base64Sig := base64.StdEncoding.EncodeToString(signature) + + triggerId := base64.StdEncoding.EncodeToString([]byte(triggerData + base64Sig)) + return clientTriggerId, triggerId, nil +} + +func (r *PostActionIntegrationRequest) GenerateTriggerId(s crypto.Signer) (string, string, *AppError) { + clientTriggerId, triggerId, err := GenerateTriggerId(r.UserId, s) + if err != nil { + return "", "", err + } + + r.TriggerId = triggerId + return clientTriggerId, triggerId, nil +} + +func DecodeAndVerifyTriggerId(triggerId string, s *ecdsa.PrivateKey) (string, string, *AppError) { + triggerIdBytes, err := base64.StdEncoding.DecodeString(triggerId) + if err != nil { + return "", "", NewAppError("DecodeAndVerifyTriggerId", "interactive_message.decode_trigger_id.base64_decode_failed", nil, err.Error(), http.StatusBadRequest) + } + + split := strings.Split(string(triggerIdBytes), ":") + if len(split) != 4 { + return "", "", NewAppError("DecodeAndVerifyTriggerId", "interactive_message.decode_trigger_id.missing_data", nil, "", http.StatusBadRequest) + } + + clientTriggerId := split[0] + userId := split[1] + timestampStr := split[2] + timestamp, _ := strconv.ParseInt(timestampStr, 10, 64) + + now := GetMillis() + if now-timestamp > INTERACTIVE_DIALOG_TRIGGER_TIMEOUT_MILLISECONDS { + return "", "", NewAppError("DecodeAndVerifyTriggerId", "interactive_message.decode_trigger_id.expired", map[string]interface{}{"Seconds": INTERACTIVE_DIALOG_TRIGGER_TIMEOUT_MILLISECONDS / 1000}, "", http.StatusBadRequest) + } + + signature, err := base64.StdEncoding.DecodeString(split[3]) + if err != nil { + return "", "", NewAppError("DecodeAndVerifyTriggerId", "interactive_message.decode_trigger_id.base64_decode_failed_signature", nil, err.Error(), http.StatusBadRequest) + } + + var esig struct { + R, S *big.Int + } + + if _, err := asn1.Unmarshal([]byte(signature), &esig); err != nil { + return "", "", NewAppError("DecodeAndVerifyTriggerId", "interactive_message.decode_trigger_id.signature_decode_failed", nil, err.Error(), http.StatusBadRequest) + } + + triggerData := strings.Join([]string{clientTriggerId, userId, timestampStr}, ":") + ":" + + h := crypto.SHA256 + sum := h.New() + sum.Write([]byte(triggerData)) + + if !ecdsa.Verify(&s.PublicKey, sum.Sum(nil), esig.R, esig.S) { + return "", "", NewAppError("DecodeAndVerifyTriggerId", "interactive_message.decode_trigger_id.verify_signature_failed", nil, "", http.StatusBadRequest) + } + + return clientTriggerId, userId, nil +} + +func (r *OpenDialogRequest) DecodeAndVerifyTriggerId(s *ecdsa.PrivateKey) (string, string, *AppError) { + return DecodeAndVerifyTriggerId(r.TriggerId, s) +} + +func (r *PostActionIntegrationRequest) ToJson() []byte { + b, _ := json.Marshal(r) + return b +} + +func PostActionIntegrationRequestFromJson(data io.Reader) *PostActionIntegrationRequest { + var o *PostActionIntegrationRequest + err := json.NewDecoder(data).Decode(&o) + if err != nil { + return nil + } + return o +} + +func (r *PostActionIntegrationResponse) ToJson() []byte { + b, _ := json.Marshal(r) + return b +} + +func PostActionIntegrationResponseFromJson(data io.Reader) *PostActionIntegrationResponse { + var o *PostActionIntegrationResponse + err := json.NewDecoder(data).Decode(&o) + if err != nil { + return nil + } + return o +} + +func SubmitDialogRequestFromJson(data io.Reader) *SubmitDialogRequest { + var o *SubmitDialogRequest + err := json.NewDecoder(data).Decode(&o) + if err != nil { + return nil + } + return o +} + +func (r *SubmitDialogRequest) ToJson() []byte { + b, _ := json.Marshal(r) + return b +} + +func SubmitDialogResponseFromJson(data io.Reader) *SubmitDialogResponse { + var o *SubmitDialogResponse + err := json.NewDecoder(data).Decode(&o) + if err != nil { + return nil + } + return o +} + +func (r *SubmitDialogResponse) ToJson() []byte { + b, _ := json.Marshal(r) + return b +} + +func (o *Post) StripActionIntegrations() { + attachments := o.Attachments() + if o.Props["attachments"] != nil { + o.Props["attachments"] = attachments + } + for _, attachment := range attachments { + for _, action := range attachment.Actions { + action.Integration = nil + } + } +} + +func (o *Post) GetAction(id string) *PostAction { + for _, attachment := range o.Attachments() { + for _, action := range attachment.Actions { + if action.Id == id { + return action + } + } + } + return nil +} + +func (o *Post) GenerateActionIds() { + if o.Props["attachments"] != nil { + o.Props["attachments"] = o.Attachments() + } + if attachments, ok := o.Props["attachments"].([]*SlackAttachment); ok { + for _, attachment := range attachments { + for _, action := range attachment.Actions { + if action.Id == "" { + action.Id = NewId() + } + } + } + } +} + +func DoPostActionRequestFromJson(data io.Reader) *DoPostActionRequest { + var o *DoPostActionRequest + json.NewDecoder(data).Decode(&o) + return o +} diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/job.go b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/job.go index c166149..76ef65b 100644 --- a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/job.go +++ b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/job.go @@ -17,6 +17,7 @@ const ( JOB_TYPE_ELASTICSEARCH_POST_AGGREGATION = "elasticsearch_post_aggregation" JOB_TYPE_LDAP_SYNC = "ldap_sync" JOB_TYPE_MIGRATIONS = "migrations" + JOB_TYPE_PLUGINS = "plugins" JOB_STATUS_PENDING = "pending" JOB_STATUS_IN_PROGRESS = "in_progress" diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/license.go b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/license.go index c30fecf..e2ef3b0 100644 --- a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/license.go +++ b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/license.go @@ -21,12 +21,14 @@ type LicenseRecord struct { } type License struct { - Id string `json:"id"` - IssuedAt int64 `json:"issued_at"` - StartsAt int64 `json:"starts_at"` - ExpiresAt int64 `json:"expires_at"` - Customer *Customer `json:"customer"` - Features *Features `json:"features"` + Id string `json:"id"` + IssuedAt int64 `json:"issued_at"` + StartsAt int64 `json:"starts_at"` + ExpiresAt int64 `json:"expires_at"` + Customer *Customer `json:"customer"` + Features *Features `json:"features"` + SkuName string `json:"sku_name"` + SkuShortName string `json:"sku_short_name"` } type Customer struct { @@ -57,7 +59,7 @@ type Features struct { CustomPermissionsSchemes *bool `json:"custom_permissions_schemes"` CustomTermsOfService *bool `json:"custom_terms_of_service"` - // after we enabled more features for webrtc we'll need to control them with this + // after we enabled more features we'll need to control them with this FutureFeatures *bool `json:"future_features"` } diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/manifest.go b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/manifest.go index 6a7df59..7a0f121 100644 --- a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/manifest.go +++ b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/manifest.go @@ -5,6 +5,7 @@ package model import ( "encoding/json" + "errors" "fmt" "io" "io/ioutil" @@ -12,6 +13,7 @@ import ( "path/filepath" "strings" + "github.com/blang/semver" "gopkg.in/yaml.v2" ) @@ -45,6 +47,8 @@ type PluginSetting struct { // // "text" will result in a string setting that can be typed in manually. // + // "longtext" will result in a multi line string that can be typed in manually. + // // "username" will result in a text setting that will autocomplete to a username. Type string `json:"type" yaml:"type"` @@ -109,6 +113,11 @@ type Manifest struct { // A version number for your plugin. Semantic versioning is recommended: http://semver.org Version string `json:"version" yaml:"version"` + // The minimum Mattermost server version required for your plugin. + // + // Minimum server version: 5.6 + MinServerVersion string `json:"min_server_version,omitempty" yaml:"min_server_version,omitempty"` + // Server defines the server-side portion of your plugin. Server *ManifestServer `json:"server,omitempty" yaml:"server,omitempty"` @@ -240,6 +249,18 @@ func (m *Manifest) HasWebapp() bool { return m.Webapp != nil } +func (m *Manifest) MeetMinServerVersion(serverVersion string) (bool, error) { + minServerVersion, err := semver.Parse(m.MinServerVersion) + if err != nil { + return false, errors.New("failed to parse MinServerVersion") + } + sv := semver.MustParse(serverVersion) + if sv.LT(minServerVersion) { + return false, nil + } + return true, nil +} + // FindManifest will find and parse the manifest in a given directory. // // In all cases other than a does-not-exist error, path is set to the path of the manifest file that was @@ -252,25 +273,23 @@ func FindManifest(dir string) (manifest *Manifest, path string, err error) { f, ferr := os.Open(path) if ferr != nil { if !os.IsNotExist(ferr) { - err = ferr - return + return nil, "", ferr } continue } b, ioerr := ioutil.ReadAll(f) f.Close() if ioerr != nil { - err = ioerr - return + return nil, path, ioerr } var parsed Manifest err = yaml.Unmarshal(b, &parsed) if err != nil { - return + return nil, path, err } manifest = &parsed manifest.Id = strings.ToLower(manifest.Id) - return + return manifest, path, nil } path = filepath.Join(dir, "plugin.json") @@ -279,16 +298,15 @@ func FindManifest(dir string) (manifest *Manifest, path string, err error) { if os.IsNotExist(ferr) { path = "" } - err = ferr - return + return nil, path, ferr } defer f.Close() var parsed Manifest err = json.NewDecoder(f).Decode(&parsed) if err != nil { - return + return nil, path, err } manifest = &parsed manifest.Id = strings.ToLower(manifest.Id) - return + return manifest, path, nil } diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/plugin_key_value.go b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/plugin_key_value.go index b7a7731..7e156d9 100644 --- a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/plugin_key_value.go +++ b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/plugin_key_value.go @@ -17,6 +17,7 @@ type PluginKeyValue struct { PluginId string `json:"plugin_id"` Key string `json:"key" db:"PKey"` Value []byte `json:"value" db:"PValue"` + ExpireAt int64 `json:"expire_at"` } func (kv *PluginKeyValue) IsValid() *AppError { diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/post.go b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/post.go index 5d2438f..8b107e4 100644 --- a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/post.go +++ b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/post.go @@ -50,8 +50,6 @@ const ( PROPS_ADD_CHANNEL_MEMBER = "add_channel_member" POST_PROPS_ADDED_USER_ID = "addedUserId" POST_PROPS_DELETE_BY = "deleteBy" - POST_ACTION_TYPE_BUTTON = "button" - POST_ACTION_TYPE_SELECT = "select" ) type Post struct { @@ -81,6 +79,9 @@ type Post struct { FileIds StringArray `json:"file_ids,omitempty"` PendingPostId string `json:"pending_post_id" db:"-"` HasReactions bool `json:"has_reactions,omitempty"` + + // Transient data populated before sending a post to the client + Metadata *PostMetadata `json:"metadata,omitempty" db:"-"` } type PostEphemeral struct { @@ -132,48 +133,16 @@ type PostForIndexing struct { ParentCreateAt *int64 `json:"parent_create_at"` } -type DoPostActionRequest struct { - SelectedOption string `json:"selected_option"` -} - -type PostAction struct { - Id string `json:"id"` - Name string `json:"name"` - Type string `json:"type"` - DataSource string `json:"data_source"` - Options []*PostActionOptions `json:"options"` - Integration *PostActionIntegration `json:"integration,omitempty"` -} - -type PostActionOptions struct { - Text string `json:"text"` - Value string `json:"value"` -} - -type PostActionIntegration struct { - URL string `json:"url,omitempty"` - Context StringInterface `json:"context,omitempty"` -} - -type PostActionIntegrationRequest struct { - UserId string `json:"user_id"` - ChannelId string `json:"channel_id"` - TeamId string `json:"team_id"` - PostId string `json:"post_id"` - Type string `json:"type"` - DataSource string `json:"data_source"` - Context StringInterface `json:"context,omitempty"` -} - -type PostActionIntegrationResponse struct { - Update *Post `json:"update"` - EphemeralText string `json:"ephemeral_text"` +// Clone shallowly copies the post. +func (o *Post) Clone() *Post { + copy := *o + return © } func (o *Post) ToJson() string { - copy := *o + copy := o.Clone() copy.StripActionIntegrations() - b, _ := json.Marshal(©) + b, _ := json.Marshal(copy) return string(b) } @@ -407,34 +376,6 @@ func (o *Post) ChannelMentions() []string { return ChannelMentions(o.Message) } -func (r *PostActionIntegrationRequest) ToJson() string { - b, _ := json.Marshal(r) - return string(b) -} - -func PostActionIntegrationRequesteFromJson(data io.Reader) *PostActionIntegrationRequest { - var o *PostActionIntegrationRequest - err := json.NewDecoder(data).Decode(&o) - if err != nil { - return nil - } - return o -} - -func (r *PostActionIntegrationResponse) ToJson() string { - b, _ := json.Marshal(r) - return string(b) -} - -func PostActionIntegrationResponseFromJson(data io.Reader) *PostActionIntegrationResponse { - var o *PostActionIntegrationResponse - err := json.NewDecoder(data).Decode(&o) - if err != nil { - return nil - } - return o -} - func (o *Post) Attachments() []*SlackAttachment { if attachments, ok := o.Props["attachments"].([]*SlackAttachment); ok { return attachments @@ -453,44 +394,6 @@ func (o *Post) Attachments() []*SlackAttachment { return ret } -func (o *Post) StripActionIntegrations() { - attachments := o.Attachments() - if o.Props["attachments"] != nil { - o.Props["attachments"] = attachments - } - for _, attachment := range attachments { - for _, action := range attachment.Actions { - action.Integration = nil - } - } -} - -func (o *Post) GetAction(id string) *PostAction { - for _, attachment := range o.Attachments() { - for _, action := range attachment.Actions { - if action.Id == id { - return action - } - } - } - return nil -} - -func (o *Post) GenerateActionIds() { - if o.Props["attachments"] != nil { - o.Props["attachments"] = o.Attachments() - } - if attachments, ok := o.Props["attachments"].([]*SlackAttachment); ok { - for _, attachment := range attachments { - for _, action := range attachment.Actions { - if action.Id == "" { - action.Id = NewId() - } - } - } - } -} - var markdownDestinationEscaper = strings.NewReplacer( `\`, `\\`, `<`, `\<`, @@ -502,12 +405,12 @@ var markdownDestinationEscaper = strings.NewReplacer( // WithRewrittenImageURLs returns a new shallow copy of the post where the message has been // rewritten via RewriteImageURLs. func (o *Post) WithRewrittenImageURLs(f func(string) string) *Post { - copy := *o + copy := o.Clone() copy.Message = RewriteImageURLs(o.Message, f) if copy.MessageSource == "" && copy.Message != o.Message { copy.MessageSource = o.Message } - return © + return copy } func (o *PostEphemeral) ToUnsanitizedJson() string { @@ -515,12 +418,6 @@ func (o *PostEphemeral) ToUnsanitizedJson() string { return string(b) } -func DoPostActionRequestFromJson(data io.Reader) *DoPostActionRequest { - var o *DoPostActionRequest - json.NewDecoder(data).Decode(&o) - return o -} - // RewriteImageURLs takes a message and returns a copy that has all of the image URLs replaced // according to the function f. For each image URL, f will be invoked, and the resulting markdown // will contain the URL returned by that invocation instead. diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/post_embed.go b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/post_embed.go new file mode 100644 index 0000000..6e8e33c --- /dev/null +++ b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/post_embed.go @@ -0,0 +1,22 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package model + +const ( + POST_EMBED_IMAGE PostEmbedType = "image" + POST_EMBED_MESSAGE_ATTACHMENT PostEmbedType = "message_attachment" + POST_EMBED_OPENGRAPH PostEmbedType = "opengraph" +) + +type PostEmbedType string + +type PostEmbed struct { + Type PostEmbedType `json:"type"` + + // The URL of the embedded content. Used for image and OpenGraph embeds. + URL string `json:"url,omitempty"` + + // Any additional data for the embedded content. Only used for OpenGraph embeds. + Data interface{} `json:"data,omitempty"` +} diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/post_metadata.go b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/post_metadata.go new file mode 100644 index 0000000..a337b2f --- /dev/null +++ b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/post_metadata.go @@ -0,0 +1,30 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package model + +type PostMetadata struct { + // Embeds holds information required to render content embedded in the post. This includes the OpenGraph metadata + // for links in the post. + Embeds []*PostEmbed `json:"embeds,omitempty"` + + // Emojis holds all custom emojis used in the post or used in reaction to the post. + Emojis []*Emoji `json:"emojis,omitempty"` + + // Files holds information about the file attachments on the post. + Files []*FileInfo `json:"files,omitempty"` + + // Images holds the dimensions of all external images in the post as a map of the image URL to its diemsnions. + // This includes image embeds (when the message contains a plaintext link to an image), Markdown images, images + // contained in the OpenGraph metadata, and images contained in message attachments. It does not contain + // the dimensions of any file attachments as those are stored in FileInfos. + Images map[string]*PostImage `json:"images,omitempty"` + + // Reactions holds reactions made to the post. + Reactions []*Reaction `json:"reactions,omitempty"` +} + +type PostImage struct { + Width int `json:"width"` + Height int `json:"height"` +} diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/preference.go b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/preference.go index 6f13c38..05379b9 100644 --- a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/preference.go +++ b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/preference.go @@ -42,6 +42,11 @@ const ( PREFERENCE_EMAIL_INTERVAL_NO_BATCHING_SECONDS = "30" // the "immediate" setting is actually 30s PREFERENCE_EMAIL_INTERVAL_BATCHING_SECONDS = "900" // fifteen minutes is 900 seconds + PREFERENCE_EMAIL_INTERVAL_IMMEDIATELY = "immediately" + PREFERENCE_EMAIL_INTERVAL_FIFTEEN = "fifteen" + PREFERENCE_EMAIL_INTERVAL_FIFTEEN_AS_SECONDS = "900" + PREFERENCE_EMAIL_INTERVAL_HOUR = "hour" + PREFERENCE_EMAIL_INTERVAL_HOUR_AS_SECONDS = "3600" ) type Preference struct { diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/saml.go b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/saml.go index 528ac45..c184b03 100644 --- a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/saml.go +++ b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/saml.go @@ -10,7 +10,7 @@ import ( const ( USER_AUTH_SERVICE_SAML = "saml" - USER_AUTH_SERVICE_SAML_TEXT = "With SAML" + USER_AUTH_SERVICE_SAML_TEXT = "SAML" ) type SamlAuthRequest struct { diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/slack_attachment.go b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/slack_attachment.go index 827bf35..273def8 100644 --- a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/slack_attachment.go +++ b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/slack_attachment.go @@ -64,7 +64,9 @@ func StringifySlackFieldValue(a []*SlackAttachment) []*SlackAttachment { // This method only parses and processes the attachments, // all else should be set in the post which is passed func ParseSlackAttachment(post *Post, attachments []*SlackAttachment) { - post.Type = POST_SLACK_ATTACHMENT + if post.Type == "" { + post.Type = POST_SLACK_ATTACHMENT + } for _, attachment := range attachments { attachment.Text = ParseSlackLinksToMarkdown(attachment.Text) diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/terms_of_service.go b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/terms_of_service.go index c99a785..e43f890 100644 --- a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/terms_of_service.go +++ b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/terms_of_service.go @@ -11,7 +11,6 @@ import ( "unicode/utf8" ) -// we only ever need the latest version of terms of service const TERMS_OF_SERVICE_CACHE_SIZE = 1 type TermsOfService struct { @@ -58,7 +57,7 @@ func InvalidTermsOfServiceError(fieldName string, termsOfServiceId string) *AppE if termsOfServiceId != "" { details = "terms_of_service_id=" + termsOfServiceId } - return NewAppError("TermsOfServiceStore.IsValid", id, map[string]interface{}{"MaxLength": POST_MESSAGE_MAX_RUNES_V2}, details, http.StatusBadRequest) + return NewAppError("TermsOfService.IsValid", id, map[string]interface{}{"MaxLength": POST_MESSAGE_MAX_RUNES_V2}, details, http.StatusBadRequest) } func (t *TermsOfService) PreSave() { diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/user.go b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/user.go index 51f54c1..6cf8506 100644 --- a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/user.go +++ b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/user.go @@ -48,33 +48,32 @@ const ( ) type User struct { - Id string `json:"id"` - CreateAt int64 `json:"create_at,omitempty"` - UpdateAt int64 `json:"update_at,omitempty"` - DeleteAt int64 `json:"delete_at"` - Username string `json:"username"` - Password string `json:"password,omitempty"` - AuthData *string `json:"auth_data,omitempty"` - AuthService string `json:"auth_service"` - Email string `json:"email"` - EmailVerified bool `json:"email_verified,omitempty"` - Nickname string `json:"nickname"` - FirstName string `json:"first_name"` - LastName string `json:"last_name"` - Position string `json:"position"` - Roles string `json:"roles"` - AllowMarketing bool `json:"allow_marketing,omitempty"` - Props StringMap `json:"props,omitempty"` - NotifyProps StringMap `json:"notify_props,omitempty"` - LastPasswordUpdate int64 `json:"last_password_update,omitempty"` - LastPictureUpdate int64 `json:"last_picture_update,omitempty"` - FailedAttempts int `json:"failed_attempts,omitempty"` - Locale string `json:"locale"` - Timezone StringMap `json:"timezone"` - MfaActive bool `json:"mfa_active,omitempty"` - MfaSecret string `json:"mfa_secret,omitempty"` - LastActivityAt int64 `db:"-" json:"last_activity_at,omitempty"` - AcceptedTermsOfServiceId string `json:"accepted_terms_of_service_id,omitempty"` // TODO remove this field when new TOS user action table is created + Id string `json:"id"` + CreateAt int64 `json:"create_at,omitempty"` + UpdateAt int64 `json:"update_at,omitempty"` + DeleteAt int64 `json:"delete_at"` + Username string `json:"username"` + Password string `json:"password,omitempty"` + AuthData *string `json:"auth_data,omitempty"` + AuthService string `json:"auth_service"` + Email string `json:"email"` + EmailVerified bool `json:"email_verified,omitempty"` + Nickname string `json:"nickname"` + FirstName string `json:"first_name"` + LastName string `json:"last_name"` + Position string `json:"position"` + Roles string `json:"roles"` + AllowMarketing bool `json:"allow_marketing,omitempty"` + Props StringMap `json:"props,omitempty"` + NotifyProps StringMap `json:"notify_props,omitempty"` + LastPasswordUpdate int64 `json:"last_password_update,omitempty"` + LastPictureUpdate int64 `json:"last_picture_update,omitempty"` + FailedAttempts int `json:"failed_attempts,omitempty"` + Locale string `json:"locale"` + Timezone StringMap `json:"timezone"` + MfaActive bool `json:"mfa_active,omitempty"` + MfaSecret string `json:"mfa_secret,omitempty"` + LastActivityAt int64 `db:"-" json:"last_activity_at,omitempty"` } type UserPatch struct { @@ -499,11 +498,7 @@ func (u *User) IsSAMLUser() bool { } func (u *User) GetPreferredTimezone() string { - if u.Timezone["useAutomaticTimezone"] == "true" { - return u.Timezone["automaticTimezone"] - } - - return u.Timezone["manualTimezone"] + return GetPreferredTimezone(u.Timezone) } // UserFromJson will decode the input and return a User @@ -639,3 +634,9 @@ func IsValidCommentsNotifyLevel(notifyLevel string) bool { notifyLevel == COMMENTS_NOTIFY_ROOT || notifyLevel == COMMENTS_NOTIFY_NEVER } + +func IsValidEmailBatchingInterval(emailInterval string) bool { + return emailInterval == PREFERENCE_EMAIL_INTERVAL_IMMEDIATELY || + emailInterval == PREFERENCE_EMAIL_INTERVAL_FIFTEEN || + emailInterval == PREFERENCE_EMAIL_INTERVAL_HOUR +} diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/user_search.go b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/user_search.go index 94596bd..68749fb 100644 --- a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/user_search.go +++ b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/user_search.go @@ -8,6 +8,10 @@ import ( "io" ) +const USER_SEARCH_MAX_LIMIT = 1000 +const USER_SEARCH_DEFAULT_LIMIT = 100 + +// UserSearch captures the parameters provided by a client for initiating a user search. type UserSearch struct { Term string `json:"term"` TeamId string `json:"team_id"` @@ -16,17 +20,38 @@ type UserSearch struct { NotInChannelId string `json:"not_in_channel_id"` AllowInactive bool `json:"allow_inactive"` WithoutTeam bool `json:"without_team"` + Limit int `json:"limit"` } // ToJson convert a User to a json string -func (u *UserSearch) ToJson() string { +func (u *UserSearch) ToJson() []byte { b, _ := json.Marshal(u) - return string(b) + return b } // UserSearchFromJson will decode the input and return a User func UserSearchFromJson(data io.Reader) *UserSearch { var us *UserSearch json.NewDecoder(data).Decode(&us) + + if us.Limit == 0 { + us.Limit = USER_SEARCH_DEFAULT_LIMIT + } + return us } + +// UserSearchOptions captures internal parameters derived from the user's permissions and a +// UserSearch request. +type UserSearchOptions struct { + // IsAdmin tracks whether or not the search is being conducted by an administrator. + IsAdmin bool + // AllowEmails allows search to examine the emails of users. + AllowEmails bool + // AllowFullNames allows search to examine the full names of users, vs. just usernames and nicknames. + AllowFullNames bool + // AllowInactive configures whether or not to return inactive users in the search results. + AllowInactive bool + // Limit limits the total number of results returned. + Limit int +} diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/user_terms_of_service.go b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/user_terms_of_service.go new file mode 100644 index 0000000..b714f92 --- /dev/null +++ b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/user_terms_of_service.go @@ -0,0 +1,61 @@ +// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package model + +import ( + "encoding/json" + "fmt" + "io" + "net/http" +) + +type UserTermsOfService struct { + UserId string `json:"user_id"` + TermsOfServiceId string `json:"terms_of_service_id"` + CreateAt int64 `json:"create_at"` +} + +func (ut *UserTermsOfService) IsValid() *AppError { + if len(ut.UserId) != 26 { + return InvalidUserTermsOfServiceError("user_id", ut.UserId) + } + + if len(ut.TermsOfServiceId) != 26 { + return InvalidUserTermsOfServiceError("terms_of_service_id", ut.UserId) + } + + if ut.CreateAt == 0 { + return InvalidUserTermsOfServiceError("create_at", ut.UserId) + } + + return nil +} + +func (ut *UserTermsOfService) ToJson() string { + b, _ := json.Marshal(ut) + return string(b) +} + +func (ut *UserTermsOfService) PreSave() { + if ut.UserId == "" { + ut.UserId = NewId() + } + + ut.CreateAt = GetMillis() +} + +func UserTermsOfServiceFromJson(data io.Reader) *UserTermsOfService { + var userTermsOfService *UserTermsOfService + json.NewDecoder(data).Decode(&userTermsOfService) + return userTermsOfService +} + +func InvalidUserTermsOfServiceError(fieldName string, userTermsOfServiceId string) *AppError { + id := fmt.Sprintf("model.user_terms_of_service.is_valid.%s.app_error", fieldName) + details := "" + if userTermsOfServiceId != "" { + details = "user_terms_of_service_user_id=" + userTermsOfServiceId + } + return NewAppError("UserTermsOfService.IsValid", id, nil, details, http.StatusBadRequest) +} diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/utils.go b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/utils.go index 172b782..849e529 100644 --- a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/utils.go +++ b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/utils.go @@ -564,3 +564,26 @@ func IsDomainName(s string) bool { return ok } + +func RemoveDuplicateStrings(in []string) []string { + out := []string{} + seen := make(map[string]bool, len(in)) + + for _, item := range in { + if !seen[item] { + out = append(out, item) + + seen[item] = true + } + } + + return out +} + +func GetPreferredTimezone(timezone StringMap) string { + if timezone["useAutomaticTimezone"] == "true" { + return timezone["automaticTimezone"] + } + + return timezone["manualTimezone"] +} diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/version.go b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/version.go index 000d754..79876a8 100644 --- a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/version.go +++ b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/version.go @@ -13,6 +13,8 @@ import ( // It should be maintained in chronological order with most current // release at the front of the list. var versions = []string{ + "5.6.0", + "5.5.0", "5.4.0", "5.3.0", "5.2.0", diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/webrtc.go b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/webrtc.go deleted file mode 100644 index 59797a5..0000000 --- a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/webrtc.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type WebrtcInfoResponse struct { - Token string `json:"token"` - GatewayUrl string `json:"gateway_url"` - StunUri string `json:"stun_uri,omitempty"` - TurnUri string `json:"turn_uri,omitempty"` - TurnPassword string `json:"turn_password,omitempty"` - TurnUsername string `json:"turn_username,omitempty"` -} - -type GatewayResponse struct { - Status string `json:"janus"` -} - -func GatewayResponseFromJson(data io.Reader) *GatewayResponse { - var o *GatewayResponse - json.NewDecoder(data).Decode(&o) - return o -} - -func (o *WebrtcInfoResponse) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func WebrtcInfoResponseFromJson(data io.Reader) *WebrtcInfoResponse { - var o *WebrtcInfoResponse - json.NewDecoder(data).Decode(&o) - return o -} diff --git a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/websocket_message.go b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/websocket_message.go index ea8872d..9cf80e7 100644 --- a/build/manifest/vendor/github.com/mattermost/mattermost-server/model/websocket_message.go +++ b/build/manifest/vendor/github.com/mattermost/mattermost-server/model/websocket_message.go @@ -37,7 +37,6 @@ const ( WEBSOCKET_EVENT_EPHEMERAL_MESSAGE = "ephemeral_message" WEBSOCKET_EVENT_STATUS_CHANGE = "status_change" WEBSOCKET_EVENT_HELLO = "hello" - WEBSOCKET_EVENT_WEBRTC = "webrtc" WEBSOCKET_AUTHENTICATION_CHALLENGE = "authentication_challenge" WEBSOCKET_EVENT_REACTION_ADDED = "reaction_added" WEBSOCKET_EVENT_REACTION_REMOVED = "reaction_removed" @@ -50,6 +49,7 @@ const ( WEBSOCKET_EVENT_ROLE_UPDATED = "role_updated" WEBSOCKET_EVENT_LICENSE_CHANGED = "license_changed" WEBSOCKET_EVENT_CONFIG_CHANGED = "config_changed" + WEBSOCKET_EVENT_OPEN_DIALOG = "open_dialog" ) type WebSocketMessage interface { diff --git a/server/Gopkg.lock b/server/Gopkg.lock index 1f156c0..75f158b 100644 --- a/server/Gopkg.lock +++ b/server/Gopkg.lock @@ -1,6 +1,14 @@ # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. +[[projects]] + digest = "1:aba270497eb2d49f5cba6f4162d524b9a1195a24cbce8be20bf56a0051f47deb" + name = "github.com/blang/semver" + packages = ["."] + pruneopts = "NUT" + revision = "2ee87856327ba09384cabd113bc6b5d174e9ec0f" + version = "v3.5.1" + [[projects]] digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec" name = "github.com/davecgh/go-spew" @@ -9,6 +17,14 @@ revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73" version = "v1.1.1" +[[projects]] + branch = "master" + digest = "1:665c8850f673be8d358fe61ab00412049e685202aa7466ae5c72ad50d89c84f7" + name = "github.com/dyatlov/go-opengraph" + packages = ["opengraph"] + pruneopts = "NUT" + revision = "816b6608b3c8c1e871bc9cf777f390e2532081fe" + [[projects]] digest = "1:1b91ae0dc69a41d4c2ed23ea5cffb721ea63f5037ca4b81e6d6771fbb8f45129" name = "github.com/fsnotify/fsnotify" @@ -48,18 +64,18 @@ revision = "a51a35ae3232254685f26a0b6d995ca0e81e2248" [[projects]] - digest = "1:58ba5285227b0f635652cd4aa82c4cfd00b590191eadd823462f0c9f64e3ae07" + digest = "1:ce8deaa2f422b7315ee4fa91f29963ed24f33eb1e1f921fe9f27ce7987776c01" name = "github.com/hashicorp/go-hclog" packages = ["."] pruneopts = "NUT" - revision = "69ff559dc25f3b435631604f573a5fa1efdb6433" + revision = "e45cbeb79f0411b1cfedd3f226ff69d5d433c762" [[projects]] - digest = "1:532090ffc3b05a7e4c0229dd2698d79149f2e0683df993224a8b202f607fb605" + digest = "1:af00abbd22cc527703068245c819a5f53567918f8c088157a4c01dd6244b58fb" name = "github.com/hashicorp/go-plugin" packages = ["."] pruneopts = "NUT" - revision = "e8d22c780116115ae5624720c9af0c97afe4f551" + revision = "a4620f9913d19f03a6bf19b2f304daaaf83ea130" [[projects]] digest = "1:11c6c696067d3127ecf332b10f89394d386d9083f82baf71f40f2da31841a009" @@ -97,7 +113,7 @@ version = "v1.8.0" [[projects]] - digest = "1:fcaa0c4871e4b49fb30d986e688c069328c042eae6ef89d0ead9882d2d450648" + digest = "1:7496e8dfee311245ba337d464a50a50af13ab59a7fde3c474c9933671c9a6eaa" name = "github.com/mattermost/mattermost-server" packages = [ "einterfaces", @@ -109,8 +125,8 @@ "utils/markdown", ] pruneopts = "NUT" - revision = "d5b613cb1bbdaa856fa126e7102d94783b9e80b6" - version = "v5.4.0" + revision = "0c1207215852a8726c3f09dea157d597fec368df" + version = "v5.6.0" [[projects]] branch = "mattermost" @@ -277,10 +293,12 @@ [[projects]] branch = "master" - digest = "1:d39e451e542c7c064d7e29050eb50993a7484d4a3b538387c0f2ac32b5b9cdd8" + digest = "1:43144a8b3203f89adbed21f991f29fb5c9fc173b1e8e1c27fc1888f6a25b9618" name = "golang.org/x/net" packages = [ "context", + "html", + "html/atom", "http/httpguts", "http2", "http2/hpack", diff --git a/server/Gopkg.toml b/server/Gopkg.toml index faa1fce..0d81a70 100644 --- a/server/Gopkg.toml +++ b/server/Gopkg.toml @@ -5,7 +5,7 @@ [[constraint]] name = "github.com/mattermost/mattermost-server" - version = "~5.4.0" + version = "~5.6.0" [[constraint]] name = "github.com/stretchr/testify"