1
0
mirror of https://github.com/mattermost/focalboard.git synced 2024-11-24 08:22:29 +02:00

Multi product architecture (#3381)

- provides support for compiling Boards directly into the Mattermost suite server
- a ServicesAPI interface replaces the PluginAPI to allow for implementations coming from pluginAPI and suite server.
- a new product package provides a place to register Boards as a suite product and handles life-cycle events
- a new boards package replaces much of the mattermost-plugin logic, allowing this to be shared between plugin and product
- Boards now uses module workspaces; run make setup-go-work
This commit is contained in:
Miguel de la Cruz 2022-07-18 19:21:57 +02:00 committed by GitHub
parent 3d753a15e5
commit 4b0fb92fba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
68 changed files with 2854 additions and 1110 deletions

4
.gitignore vendored
View File

@ -18,6 +18,10 @@ pids
.vscode
*.code-workspace
# golang
go.work
go.work.sum
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

View File

@ -39,7 +39,10 @@ prebuild: ## Run prebuild actions (install dependencies etc.).
ci: webapp-ci server-test ## Simulate CI, locally.
templates-archive: ## Build templates archive file
setup-go-work: ## Sets up a go.work file
go run ./mattermost-plugin/build/gowork/main.go
templates-archive: setup-go-work ## Build templates archive file
cd server/assets/build-template-archive; go run -tags '$(BUILD_TAGS)' main.go --dir="../templates-boardarchive" --out="../templates.boardarchive"
server: templates-archive ## Build server for local environment.

View File

@ -4,12 +4,10 @@ go 1.18
replace github.com/mattermost/focalboard/server => ../server
replace github.com/mattermost/mattermost-server/v6 => github.com/mattermost/mattermost-server/v6 v6.0.0-20220601144141-e54977931ccd
require (
github.com/google/uuid v1.3.0
github.com/mattermost/focalboard/server v0.0.0-00010101000000-000000000000
github.com/mattermost/mattermost-server/v6 v6.3.0
github.com/mattermost/mattermost-server/v6 v6.0.0-20220711175838-7ee7523729e6
github.com/webview/webview v0.0.0-20220314230258-a2b7746141c3
)
@ -17,7 +15,6 @@ require (
github.com/Masterminds/squirrel v1.5.2 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver v3.5.1+incompatible // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
@ -31,33 +28,29 @@ require (
github.com/gorilla/mux v1.8.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/graph-gophers/graphql-go v1.4.0 // indirect
github.com/hashicorp/go-hclog v1.2.0 // indirect
github.com/hashicorp/go-plugin v1.4.4 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/klauspost/compress v1.15.3 // indirect
github.com/klauspost/cpuid/v2 v2.0.12 // indirect
github.com/klauspost/compress v1.15.6 // indirect
github.com/klauspost/cpuid/v2 v2.0.13 // indirect
github.com/krolaw/zipstream v0.0.0-20180621105154-0a2661891f94 // indirect
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
github.com/lib/pq v1.10.5 // indirect
github.com/lib/pq v1.10.6 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404 // indirect
github.com/mattermost/ldap v0.0.0-20201202150706-ee0e6284187d // indirect
github.com/mattermost/logr/v2 v2.0.15 // indirect
github.com/mattermost/mattermost-plugin-api v0.0.27 // indirect
github.com/mattermost/mattermost-plugin-api v0.0.28-0.20220623051512-0afd85e854d4 // indirect
github.com/mattermost/morph v0.0.0-20220401091636-39f834798da8 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/minio-go/v7 v7.0.26 // indirect
github.com/minio/minio-go/v7 v7.0.28 // indirect
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/mitchellh/mapstructure v1.4.3 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
@ -69,7 +62,7 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.12.1 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/common v0.33.0 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/rs/xid v1.4.0 // indirect
@ -81,7 +74,7 @@ require (
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.10.1 // indirect
github.com/stretchr/testify v1.7.1 // indirect
github.com/stretchr/testify v1.7.2 // indirect
github.com/subosito/gotenv v1.2.0 // indirect
github.com/tidwall/gjson v1.14.1 // indirect
github.com/tidwall/match v1.1.1 // indirect
@ -93,20 +86,17 @@ require (
github.com/wiggin77/srslog v1.0.1 // indirect
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect
github.com/yuin/goldmark v1.4.12 // indirect
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122 // indirect
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 // indirect
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/net v0.0.0-20220614195744-fb05da6f9022 // indirect
golang.org/x/sys v0.0.0-20220614162138-6c1b26c55098 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/tools v0.1.10 // indirect
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3 // indirect
google.golang.org/grpc v1.46.0 // indirect
golang.org/x/tools v0.1.11 // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/ini.v1 v1.66.4 // indirect
gopkg.in/ini.v1 v1.66.6 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/uint128 v1.2.0 // indirect
modernc.org/cc/v3 v3.35.24 // indirect
modernc.org/ccgo/v3 v3.15.17 // indirect

View File

@ -130,6 +130,7 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/RoaringBitmap/roaring v0.9.4/go.mod h1:icnadbWcNyfEHlYdr+tDlOTih1Bf/h+rzPpv4sbomAA=
github.com/RoaringBitmap/roaring v1.2.1/go.mod h1:icnadbWcNyfEHlYdr+tDlOTih1Bf/h+rzPpv4sbomAA=
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
github.com/advancedlogic/GoOse v0.0.0-20191112112754-e742535969c1/go.mod h1:f3HCSN1fBWjcpGtXyM119MJgeQl838v6so/PQOqvE1w=
@ -164,7 +165,7 @@ github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:l
github.com/avct/uasurfer v0.0.0-20191028135549-26b5daa857f1/go.mod h1:noBAuukeYOXa0aXGqxr24tADqkwDO2KRD15FsuaZ5a8=
github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.44.9/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go v1.44.34/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go-v2 v1.8.0/go.mod h1:xEFuWz+3TYdlPRuo+CqATbeDWIWyaT5uAPwPaWtgse0=
github.com/aws/aws-sdk-go-v2 v1.9.2/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
github.com/aws/aws-sdk-go-v2/config v1.6.0/go.mod h1:TNtBVmka80lRPk5+S9ZqVfFszOQAGJJ9KbT3EM3CHNU=
@ -210,27 +211,34 @@ github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqO
github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/blevesearch/bleve/v2 v2.3.2/go.mod h1:96+xE5pZUOsr3Y4vHzV1cBC837xZCpwLlX0hrrxnvIg=
github.com/blevesearch/bleve_index_api v1.0.1/go.mod h1:fiwKS0xLEm+gBRgv5mumf0dhgFr2mDgZah1pqv1c1M4=
github.com/blevesearch/bleve_index_api v1.0.2/go.mod h1:fiwKS0xLEm+gBRgv5mumf0dhgFr2mDgZah1pqv1c1M4=
github.com/blevesearch/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:9eJDeqxJ3E7WnLebQUlPD7ZjSce7AnDb9vjGmMCbD0A=
github.com/blevesearch/go-porterstemmer v1.0.3/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M=
github.com/blevesearch/goleveldb v1.0.1/go.mod h1:WrU8ltZbIp0wAoig/MHbrPCXSOLpe79nz5lv5nqfYrQ=
github.com/blevesearch/gtreap v0.1.1/go.mod h1:QaQyDRAT51sotthUWAH4Sj08awFSSWzgYICSZ3w0tYk=
github.com/blevesearch/mmap-go v1.0.2/go.mod h1:ol2qBqYaOUsGdm7aRMRrYGgPvnwLe6Y+7LMvAB5IbSA=
github.com/blevesearch/mmap-go v1.0.3/go.mod h1:pYvKl/grLQrBxuaRYgoTssa4rVujYYeenDp++2E+yvs=
github.com/blevesearch/mmap-go v1.0.4/go.mod h1:EWmEAOmdAS9z/pi/+Toxu99DnsbhG1TIxUoRmJw/pSs=
github.com/blevesearch/scorch_segment_api/v2 v2.1.0/go.mod h1:uch7xyyO/Alxkuxa+CGs79vw0QY8BENSBjg6Mw5L5DE=
github.com/blevesearch/segment v0.9.0/go.mod h1:9PfHYUdQCgHktBgvtUOF4x+pc4/l8rdH0u5spnW85UQ=
github.com/blevesearch/snowball v0.6.1/go.mod h1:ZF0IBg5vgpeoUhnMza2v0A/z8m1cWPlwhke08LpNusg=
github.com/blevesearch/snowballstem v0.9.0/go.mod h1:PivSj3JMc8WuaFkTSRDW2SlrulNWPl4ABg1tC/hlgLs=
github.com/blevesearch/upsidedown_store_api v1.0.1/go.mod h1:MQDVGpHZrpe3Uy26zJBf/a8h0FZY6xJbthIMm8myH2Q=
github.com/blevesearch/vellum v1.0.7/go.mod h1:doBZpmRhwTsASB4QdUZANlJvqVAUdUyX0ZK7QJCTeBE=
github.com/blevesearch/vellum v1.0.8/go.mod h1:+cpRi/tqq49xUYSQN2P7A5zNSNrS+MscLeeaZ3J46UA=
github.com/blevesearch/zapx/v11 v11.3.3/go.mod h1:YzTfUm4kS3e8OmTXDHVV8OzC5MWPO/VPJZQgPNVb4Lc=
github.com/blevesearch/zapx/v11 v11.3.4/go.mod h1:HJ7qdfBxdziuymKvXbsBVhCK5pB98tdzQbc8pJV6tJo=
github.com/blevesearch/zapx/v12 v12.3.3/go.mod h1:RMl6lOZqF+sTxKvhQDJ5yK2LT3Mu7E2p/jGdjAaiRxs=
github.com/blevesearch/zapx/v12 v12.3.4/go.mod h1:uQrKrK9XjXAAsJfAIE8ViLqIKP/keA2DQhS1XXpjkwA=
github.com/blevesearch/zapx/v13 v13.3.3/go.mod h1:eppobNM35U4C22yDvTuxV9xPqo10pwfP/jugL4INWG4=
github.com/blevesearch/zapx/v13 v13.3.4/go.mod h1:Wl7hO1gT+IDvJb7i06g2iW5Qvw0KzncJPsBx7WGWhLA=
github.com/blevesearch/zapx/v14 v14.3.3/go.mod h1:zXNcVzukh0AvG57oUtT1T0ndi09H0kELNaNmekEy0jw=
github.com/blevesearch/zapx/v14 v14.3.4/go.mod h1:b1YhRXXhAj9i+9aOwhRKCHUmJyYieK/QbDvPJDLddUk=
github.com/blevesearch/zapx/v15 v15.3.3/go.mod h1:C+f/97ZzTzK6vt/7sVlZdzZxKu+5+j4SrGCvr9dJzaY=
github.com/blevesearch/zapx/v15 v15.3.4/go.mod h1:TQ/qDC2q7TSSpeC6Vgr9fDN56Ra0u49lZJQ4v30WEx4=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
@ -526,10 +534,12 @@ github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3I
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
@ -767,8 +777,8 @@ github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brv
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM=
github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-hclog v1.2.1 h1:YQsLlGDJgwhXFpucSPyVbCBviQtjlHv3jLTlp8YmtEw=
github.com/hashicorp/go-hclog v1.2.1/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
@ -861,7 +871,6 @@ github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0/go.mod h1:CVKl
github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
github.com/jaytaylor/html2text v0.0.0-20211105163654-bc68cce691ba/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE=
github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
@ -920,16 +929,16 @@ github.com/klauspost/compress v1.13.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.3 h1:wmfu2iqj9q22SyMINp1uQ8C2/V4M1phJdmH9fG4nba0=
github.com/klauspost/compress v1.15.3/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/klauspost/compress v1.15.6 h1:6D9PcO8QWu0JyaQ2zUMmu16T1T+zjjEpP91guRsvDfY=
github.com/klauspost/compress v1.15.6/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4=
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE=
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/cpuid/v2 v2.0.13 h1:1XxvOiqXZ8SULZUKim/wncr3wZ38H4yCuVDvKdK9OGs=
github.com/klauspost/cpuid/v2 v2.0.13/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@ -966,9 +975,8 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.5 h1:J+gdV2cUmX7ZqL2B0lFcW0m+egaHC2V3lpO8nWxyYiQ=
github.com/lib/pq v1.10.5/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs=
github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w=
@ -994,10 +1002,11 @@ github.com/mattermost/ldap v0.0.0-20201202150706-ee0e6284187d h1:/RJ/UV7M5c7L2TQ
github.com/mattermost/ldap v0.0.0-20201202150706-ee0e6284187d/go.mod h1:HLbgMEI5K131jpxGazJ97AxfPDt31osq36YS1oxFQPQ=
github.com/mattermost/logr/v2 v2.0.15 h1:+WNbGcsc3dBao65eXlceB6dTILNJRIrvubnsTl3zBew=
github.com/mattermost/logr/v2 v2.0.15/go.mod h1:mpPp935r5dIkFDo2y9Q87cQWhFR/4xXpNh0k/y8Hmwg=
github.com/mattermost/mattermost-plugin-api v0.0.27 h1:zFKQ6JW1/f0MfR5dP9P2umNNYVcLtTO74mM/PrVPNC4=
github.com/mattermost/mattermost-plugin-api v0.0.27/go.mod h1:MM+tZ+36Obm9jqcveoxY2RFbwLaZKZUgR1zUlc0UBYw=
github.com/mattermost/mattermost-server/v6 v6.0.0-20220601144141-e54977931ccd h1:Aio3uqGOhAUZKrsQqdtFHxlJ8EgRmsssy1FxOZIS3vk=
github.com/mattermost/mattermost-server/v6 v6.0.0-20220601144141-e54977931ccd/go.mod h1:HBSu5YC0k8TLb+7DFFB9/63/+oBZj7pgx8K07lHmzyI=
github.com/mattermost/mattermost-plugin-api v0.0.28-0.20220623051512-0afd85e854d4 h1:TF1yBBsLntuNb3wc3DRg30S9i6tv1JwtREtXd7Gnv9E=
github.com/mattermost/mattermost-plugin-api v0.0.28-0.20220623051512-0afd85e854d4/go.mod h1:jtiaM6selJi1Od1zGZDGO78hZyG0gI4/I2/8mza4OZg=
github.com/mattermost/mattermost-server/v6 v6.0.0-20220622145221-00016e3a4ff4/go.mod h1:e2CtTtnty6oH8CiHm40cMOqJ+dJeWEK39/tobCkeMAk=
github.com/mattermost/mattermost-server/v6 v6.0.0-20220711175838-7ee7523729e6 h1:lfkO5s/ZwuD2esAHGX+0EtmcsAVXJ0S5Xn37uWW/WoQ=
github.com/mattermost/mattermost-server/v6 v6.0.0-20220711175838-7ee7523729e6/go.mod h1:e2CtTtnty6oH8CiHm40cMOqJ+dJeWEK39/tobCkeMAk=
github.com/mattermost/morph v0.0.0-20220401091636-39f834798da8 h1:gwliVjCTqAC01mSCNqa5nJ/4MmGq50vrjsottIhQ4d8=
github.com/mattermost/morph v0.0.0-20220401091636-39f834798da8/go.mod h1:jxM3g1bx+k2Thz7jofcHguBS8TZn5Pc+o5MGmORObhw=
github.com/mattermost/rsc v0.0.0-20160330161541-bbaefb05eaa0/go.mod h1:nV5bfVpT//+B1RPD2JvRnxbkLmJEYXmRaaVl15fsXjs=
@ -1053,8 +1062,8 @@ github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WT
github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw=
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
github.com/minio/minio-go/v7 v7.0.26 h1:D0HK+8793etZfRY/vHhDmFaP+vmT41K3K4JV9vmZCBQ=
github.com/minio/minio-go/v7 v7.0.26/go.mod h1:x81+AX5gHSfCSqw7jxRKHvxUXMlE5uKX0Vb75Xk5yYg=
github.com/minio/minio-go/v7 v7.0.28 h1:VMr3K5qGIEt+/KW3poopRh8mzi5RwuCjmrmstK196Fg=
github.com/minio/minio-go/v7 v7.0.28/go.mod h1:x81+AX5gHSfCSqw7jxRKHvxUXMlE5uKX0Vb75Xk5yYg=
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
@ -1254,8 +1263,9 @@ github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.33.0 h1:rHgav/0a6+uYgGdNt3jwz8FNSesO/Hsang3O0T9A5SE=
github.com/prometheus/common v0.33.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE=
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
@ -1295,7 +1305,6 @@ github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY=
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/rudderlabs/analytics-go v3.3.1+incompatible/go.mod h1:LF8/ty9kUX4PTY3l5c97K3nZZaX5Hwsvt+NBaRL/f30=
github.com/rudderlabs/analytics-go v3.3.2+incompatible h1:bDajEJTYhfHjNYxbQFMA/2dHlOjyeSgxS7GPIdMZ52Q=
github.com/rudderlabs/analytics-go v3.3.2+incompatible/go.mod h1:LF8/ty9kUX4PTY3l5c97K3nZZaX5Hwsvt+NBaRL/f30=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
@ -1418,8 +1427,9 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
@ -1608,8 +1618,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122 h1:NvGWuYG8dkDHFSKksI1P9faiVJ9rayE6l0+ouWVIDs8=
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM=
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -1635,7 +1645,7 @@ golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+o
golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/image v0.0.0-20220601225756-64ec528b34cd/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@ -1662,8 +1672,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -1742,8 +1752,8 @@ golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20220111093109-d55c255bac03/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220614195744-fb05da6f9022 h1:0qjDla5xICC2suMtyRH/QqX3B1btXTfNsIt/i4LFgO0=
golang.org/x/net v0.0.0-20220614195744-fb05da6f9022/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -1765,6 +1775,7 @@ golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -1778,6 +1789,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180224232135-f6cff0780e54/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -1910,8 +1922,10 @@ golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220317061510-51cd9980dadf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220614162138-6c1b26c55098 h1:PgOr27OhUx2IRqGJ2RxAWI4dJQ7bi9cSrB82uzFzfUA=
golang.org/x/sys v0.0.0-20220614162138-6c1b26c55098/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@ -2021,16 +2035,16 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/tools v0.1.11 h1:loJ25fNOEhSXfHrpoGj91eCUThwdNX6u24rO1xnNteY=
golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0=
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0=
@ -2161,8 +2175,8 @@ google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ6
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220111164026-67b88f271998/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3 h1:q1kiSVscqoDeqTF27eQ2NnLLDmqF0I373qQNXYMy0fo=
google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
google.golang.org/genproto v0.0.0-20220614165028-45ed7f3ff16e h1:ubR4JUtqN3ffdFjpKylv8scWk/mZstGmzXbgYSkuMl0=
google.golang.org/genproto v0.0.0-20220614165028-45ed7f3ff16e/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
@ -2200,8 +2214,8 @@ google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9K
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
google.golang.org/grpc v1.46.0 h1:oCjezcn6g6A75TGoKYBPgKmVBLexhYLM6MebdrPApP8=
google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8=
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@ -2238,8 +2252,8 @@ gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4=
gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI=
gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
@ -2264,8 +2278,9 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/postgres v1.0.8/go.mod h1:4eOzrI1MUfm6ObJU/UcmbXyiHSs8jSwH95G5P5dxcAg=
gorm.io/gorm v1.20.12/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.21.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=

View File

@ -60,6 +60,9 @@ all: check-style test dist
apply:
./build/bin/manifest apply
setup-go-work: ## Sets up a go.work file
cd ..; go run ./mattermost-plugin/build/gowork/main.go
## Runs eslint and golangci-lint
.PHONY: check-style
check-style: webapp/node_modules
@ -80,7 +83,7 @@ ifneq ($(HAS_SERVER),)
golangci-lint run ./...
endif
templates-archive: ## Build templates archive file
templates-archive: setup-go-work ## Build templates archive file
cd ../server/assets/build-template-archive; go run -tags '$(BUILD_TAGS)' main.go --dir="../templates-boardarchive" --out="../templates.boardarchive"
## Builds the server, if it exists, for all supported architectures.

View File

@ -2,13 +2,11 @@ module github.com/mattermost/mattermost-plugin-starter-template/build
go 1.18
replace github.com/mattermost/mattermost-server/v6 => github.com/mattermost/mattermost-server/v6 v6.0.0-20220601144141-e54977931ccd
require (
github.com/go-git/go-git/v5 v5.1.0
github.com/mattermost/mattermost-server/v6 v6.0.0-20220601144141-e54977931ccd
github.com/mattermost/mattermost-server/v6 v6.0.0-20220705131644-b99bd0d04915
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.7.1
github.com/stretchr/testify v1.7.2
sigs.k8s.io/yaml v1.2.0
)
@ -25,17 +23,17 @@ require (
github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/graph-gophers/graphql-go v1.4.0 // indirect
github.com/imdario/mergo v0.3.9 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect
github.com/klauspost/compress v1.15.3 // indirect
github.com/klauspost/cpuid/v2 v2.0.12 // indirect
github.com/klauspost/compress v1.15.6 // indirect
github.com/klauspost/cpuid/v2 v2.0.13 // indirect
github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404 // indirect
github.com/mattermost/ldap v0.0.0-20201202150706-ee0e6284187d // indirect
github.com/mattermost/logr/v2 v2.0.15 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/minio-go/v7 v7.0.26 // indirect
github.com/minio/minio-go/v7 v7.0.28 // indirect
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
@ -53,13 +51,13 @@ require (
github.com/wiggin77/merror v1.0.3 // indirect
github.com/wiggin77/srslog v1.0.1 // indirect
github.com/xanzy/ssh-agent v0.2.1 // indirect
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122 // indirect
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 // indirect
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect
golang.org/x/net v0.0.0-20220614195744-fb05da6f9022 // indirect
golang.org/x/sys v0.0.0-20220614162138-6c1b26c55098 // indirect
golang.org/x/text v0.3.7 // indirect
gopkg.in/ini.v1 v1.66.4 // indirect
gopkg.in/ini.v1 v1.66.6 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@ -84,8 +84,9 @@ github.com/graph-gophers/graphql-go v1.4.0 h1:JE9wveRTSXwJyjdRd6bOQ7Ob5bewTUQ58J
github.com/graph-gophers/graphql-go v1.4.0/go.mod h1:YtmJZDLbF1YYNrlNAuiO5zAStUWc3XZT07iGsVqe1Os=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg=
github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
@ -97,12 +98,12 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY=
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.15.3 h1:wmfu2iqj9q22SyMINp1uQ8C2/V4M1phJdmH9fG4nba0=
github.com/klauspost/compress v1.15.3/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/klauspost/compress v1.15.6 h1:6D9PcO8QWu0JyaQ2zUMmu16T1T+zjjEpP91guRsvDfY=
github.com/klauspost/compress v1.15.6/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE=
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/cpuid/v2 v2.0.13 h1:1XxvOiqXZ8SULZUKim/wncr3wZ38H4yCuVDvKdK9OGs=
github.com/klauspost/cpuid/v2 v2.0.13/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@ -117,14 +118,14 @@ github.com/mattermost/ldap v0.0.0-20201202150706-ee0e6284187d h1:/RJ/UV7M5c7L2TQ
github.com/mattermost/ldap v0.0.0-20201202150706-ee0e6284187d/go.mod h1:HLbgMEI5K131jpxGazJ97AxfPDt31osq36YS1oxFQPQ=
github.com/mattermost/logr/v2 v2.0.15 h1:+WNbGcsc3dBao65eXlceB6dTILNJRIrvubnsTl3zBew=
github.com/mattermost/logr/v2 v2.0.15/go.mod h1:mpPp935r5dIkFDo2y9Q87cQWhFR/4xXpNh0k/y8Hmwg=
github.com/mattermost/mattermost-server/v6 v6.0.0-20220601144141-e54977931ccd h1:Aio3uqGOhAUZKrsQqdtFHxlJ8EgRmsssy1FxOZIS3vk=
github.com/mattermost/mattermost-server/v6 v6.0.0-20220601144141-e54977931ccd/go.mod h1:HBSu5YC0k8TLb+7DFFB9/63/+oBZj7pgx8K07lHmzyI=
github.com/mattermost/mattermost-server/v6 v6.0.0-20220705131644-b99bd0d04915 h1:W7y+l87t0qORLQMFXtz/s9rxftWZDop8Es6wYQLr5vk=
github.com/mattermost/mattermost-server/v6 v6.0.0-20220705131644-b99bd0d04915/go.mod h1:e2CtTtnty6oH8CiHm40cMOqJ+dJeWEK39/tobCkeMAk=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
github.com/minio/minio-go/v7 v7.0.26 h1:D0HK+8793etZfRY/vHhDmFaP+vmT41K3K4JV9vmZCBQ=
github.com/minio/minio-go/v7 v7.0.26/go.mod h1:x81+AX5gHSfCSqw7jxRKHvxUXMlE5uKX0Vb75Xk5yYg=
github.com/minio/minio-go/v7 v7.0.28 h1:VMr3K5qGIEt+/KW3poopRh8mzi5RwuCjmrmstK196Fg=
github.com/minio/minio-go/v7 v7.0.28/go.mod h1:x81+AX5gHSfCSqw7jxRKHvxUXMlE5uKX0Vb75Xk5yYg=
github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
@ -194,8 +195,9 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/tinylib/msgp v1.1.6 h1:i+SbKraHhnrf9M5MYmvQhFnbLhAXSDWF8WWsuyRdocw=
github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOMufyw=
@ -226,8 +228,8 @@ golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122 h1:NvGWuYG8dkDHFSKksI1P9faiVJ9rayE6l0+ouWVIDs8=
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM=
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@ -245,8 +247,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220614195744-fb05da6f9022 h1:0qjDla5xICC2suMtyRH/QqX3B1btXTfNsIt/i4LFgO0=
golang.org/x/net v0.0.0-20220614195744-fb05da6f9022/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -268,8 +270,8 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220614162138-6c1b26c55098 h1:PgOr27OhUx2IRqGJ2RxAWI4dJQ7bi9cSrB82uzFzfUA=
golang.org/x/sys v0.0.0-20220614162138-6c1b26c55098/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -311,8 +313,8 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4=
gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI=
gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
@ -321,11 +323,12 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -0,0 +1,93 @@
package main
import (
"fmt"
"os"
"strings"
)
const (
filename = "go.work"
)
func main() {
force := false
if len(os.Args) == 2 && strings.ToLower(os.Args[1]) == "-f" {
force = true
}
if _, err := os.Stat(filename); err == nil && !force {
// go.work already exists and force flag not specified
fmt.Fprintln(os.Stdout, "go.work already exists and -f (force) not specified; nothing to do.")
os.Exit(0)
}
f, err := os.Create(filename)
if err != nil {
fmt.Fprintf(os.Stderr, "error creating %s: %s", filename, err.Error())
os.Exit(-1)
}
defer f.Close()
isCI := isCI()
content := makeGoWork(isCI)
_, err = f.WriteString(content)
if err != nil {
fmt.Fprintf(os.Stderr, "error writing %s: %s", filename, err.Error())
os.Exit(-1)
}
fmt.Fprintln(os.Stdout, "go.work written successfully.")
}
func makeGoWork(ci bool) string {
var b strings.Builder
b.WriteString("go 1.18\n\n")
b.WriteString("use ./mattermost-plugin\n")
b.WriteString("use ./server\n")
if ci {
b.WriteString("use ./linux\n")
} else {
b.WriteString("use ../mattermost-server\n")
b.WriteString("use ../enterprise\n")
}
return b.String()
}
func isCI() bool {
vars := map[string]bool{
// var name: must_be_true (false means being defined is enough)
"CIRCLECI": true,
"GITHUB_ACTIONS": true,
"GITLAB_CI": false,
"TRAVIS": true,
}
for name, mustBeTrue := range vars {
if isEnvVarTrue(name, mustBeTrue) {
return true
}
}
return false
}
func isEnvVarTrue(name string, mustBeTrue bool) bool {
val, ok := os.LookupEnv(name)
if !ok {
return false
}
if !mustBeTrue {
return true
}
switch strings.ToLower(val) {
case "t", "1", "true", "y", "yes":
return true
}
return false
}

View File

@ -2,16 +2,10 @@ module github.com/mattermost/focalboard/mattermost-plugin
go 1.18
replace github.com/mattermost/focalboard/server => ../server
replace github.com/mattermost/mattermost-server/v6 => github.com/mattermost/mattermost-server/v6 v6.0.0-20220613202234-182ae1234a49
require (
github.com/golang/mock v1.6.0
github.com/mattermost/focalboard/server v0.0.0-00010101000000-000000000000
github.com/mattermost/mattermost-plugin-api v0.0.27
github.com/mattermost/mattermost-server/v6 v6.3.0
github.com/stretchr/testify v1.7.1
github.com/mattermost/mattermost-plugin-api v0.0.28-0.20220623051512-0afd85e854d4
github.com/stretchr/testify v1.7.2
)
require (
@ -20,33 +14,33 @@ require (
github.com/Masterminds/semver/v3 v3.1.1 // indirect
github.com/Masterminds/squirrel v1.5.2 // indirect
github.com/PuerkitoBio/goquery v1.8.0 // indirect
github.com/RoaringBitmap/roaring v0.9.4 // indirect
github.com/RoaringBitmap/roaring v1.2.1 // indirect
github.com/advancedlogic/GoOse v0.0.0-20210820140952-9d5822d4a625 // indirect
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/andybalholm/cascadia v1.3.1 // indirect
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de // indirect
github.com/avct/uasurfer v0.0.0-20191028135549-26b5daa857f1 // indirect
github.com/aws/aws-sdk-go v1.44.9 // indirect
github.com/aws/aws-sdk-go v1.44.34 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.2.2 // indirect
github.com/blang/semver v3.5.1+incompatible // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/blevesearch/bleve/v2 v2.3.2 // indirect
github.com/blevesearch/bleve_index_api v1.0.1 // indirect
github.com/blevesearch/bleve_index_api v1.0.2 // indirect
github.com/blevesearch/go-porterstemmer v1.0.3 // indirect
github.com/blevesearch/gtreap v0.1.1 // indirect
github.com/blevesearch/mmap-go v1.0.3 // indirect
github.com/blevesearch/mmap-go v1.0.4 // indirect
github.com/blevesearch/scorch_segment_api/v2 v2.1.0 // indirect
github.com/blevesearch/segment v0.9.0 // indirect
github.com/blevesearch/snowballstem v0.9.0 // indirect
github.com/blevesearch/upsidedown_store_api v1.0.1 // indirect
github.com/blevesearch/vellum v1.0.7 // indirect
github.com/blevesearch/zapx/v11 v11.3.3 // indirect
github.com/blevesearch/zapx/v12 v12.3.3 // indirect
github.com/blevesearch/zapx/v13 v13.3.3 // indirect
github.com/blevesearch/zapx/v14 v14.3.3 // indirect
github.com/blevesearch/zapx/v15 v15.3.3 // indirect
github.com/blevesearch/vellum v1.0.8 // indirect
github.com/blevesearch/zapx/v11 v11.3.4 // indirect
github.com/blevesearch/zapx/v12 v12.3.4 // indirect
github.com/blevesearch/zapx/v13 v13.3.4 // indirect
github.com/blevesearch/zapx/v14 v14.3.4 // indirect
github.com/blevesearch/zapx/v15 v15.3.4 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
@ -79,7 +73,7 @@ require (
github.com/gorilla/websocket v1.5.0 // indirect
github.com/graph-gophers/graphql-go v1.4.0 // indirect
github.com/h2non/go-is-svg v0.0.0-20160927212452-35e8c4b0612c // indirect
github.com/hashicorp/go-hclog v1.2.0 // indirect
github.com/hashicorp/go-hclog v1.2.1 // indirect
github.com/hashicorp/go-plugin v1.4.4 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
@ -89,19 +83,20 @@ require (
github.com/jmoiron/sqlx v1.3.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/klauspost/compress v1.15.3 // indirect
github.com/klauspost/cpuid/v2 v2.0.12 // indirect
github.com/klauspost/compress v1.15.6 // indirect
github.com/klauspost/cpuid/v2 v2.0.13 // indirect
github.com/klauspost/pgzip v1.2.5 // indirect
github.com/krolaw/zipstream v0.0.0-20180621105154-0a2661891f94 // indirect
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 // indirect
github.com/levigross/exp-html v0.0.0-20120902181939-8df60c69a8f5 // indirect
github.com/lib/pq v1.10.5 // indirect
github.com/lib/pq v1.10.6 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404 // indirect
github.com/mattermost/ldap v0.0.0-20201202150706-ee0e6284187d // indirect
github.com/mattermost/logr/v2 v2.0.15 // indirect
github.com/mattermost/mattermost-server/v6 v6.0.0-20220711175838-7ee7523729e6 // indirect
github.com/mattermost/morph v0.0.0-20220401091636-39f834798da8 // indirect
github.com/mattermost/rsc v0.0.0-20160330161541-bbaefb05eaa0 // indirect
github.com/mattermost/squirrel v0.2.0 // indirect
@ -113,7 +108,7 @@ require (
github.com/mholt/archiver/v3 v3.5.1 // indirect
github.com/microcosm-cc/bluemonday v1.0.18 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/minio-go/v7 v7.0.26 // indirect
github.com/minio/minio-go/v7 v7.0.28 // indirect
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
@ -177,24 +172,23 @@ require (
github.com/yuin/goldmark v1.4.12 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
go.uber.org/atomic v1.9.0 // indirect
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122 // indirect
golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9 // indirect
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 // indirect
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect
golang.org/x/image v0.0.0-20220601225756-64ec528b34cd // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/net v0.0.0-20220614195744-fb05da6f9022 // indirect
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect
golang.org/x/sys v0.0.0-20220614162138-6c1b26c55098 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/tools v0.1.10 // indirect
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3 // indirect
google.golang.org/grpc v1.46.0 // indirect
golang.org/x/tools v0.1.11 // indirect
google.golang.org/genproto v0.0.0-20220614165028-45ed7f3ff16e // indirect
google.golang.org/grpc v1.47.0 // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/ini.v1 v1.66.4 // indirect
gopkg.in/ini.v1 v1.66.6 // indirect
gopkg.in/mail.v2 v2.3.1 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/uint128 v1.2.0 // indirect
modernc.org/cc/v3 v3.35.24 // indirect
modernc.org/ccgo/v3 v3.15.17 // indirect

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,209 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package product
import (
"database/sql"
"github.com/mattermost/mattermost-server/v6/app/request"
mm_model "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
"github.com/mattermost/focalboard/server/model"
)
// normalizeAppError returns a truly nil error if appErr is nil
// See https://golang.org/doc/faq#nil_error for more details.
func normalizeAppErr(appErr *mm_model.AppError) error {
if appErr == nil {
return nil
}
return appErr
}
// serviceAPIAdapter is an adapter that flattens the APIs provided by suite services so they can
// be used as per the Plugin API.
// Note: when supporting a plugin build is no longer needed this adapter may be removed as the Boards app
// can be modified to use the services in modular fashion.
type serviceAPIAdapter struct {
api *boardsProduct
ctx *request.Context
}
func newServiceAPIAdapter(api *boardsProduct) *serviceAPIAdapter {
return &serviceAPIAdapter{
api: api,
ctx: &request.Context{},
}
}
//
// Channels service.
//
func (a *serviceAPIAdapter) GetDirectChannel(userID1, userID2 string) (*mm_model.Channel, error) {
channel, appErr := a.api.channelService.GetDirectChannel(userID1, userID2)
return channel, normalizeAppErr(appErr)
}
func (a *serviceAPIAdapter) GetChannelByID(channelID string) (*mm_model.Channel, error) {
channel, appErr := a.api.channelService.GetChannelByID(channelID)
return channel, normalizeAppErr(appErr)
}
func (a *serviceAPIAdapter) GetChannelMember(channelID string, userID string) (*mm_model.ChannelMember, error) {
member, appErr := a.api.channelService.GetChannelMember(channelID, userID)
return member, normalizeAppErr(appErr)
}
func (a *serviceAPIAdapter) GetChannelsForTeamForUser(teamID string, userID string, includeDeleted bool) (mm_model.ChannelList, error) {
opts := &mm_model.ChannelSearchOpts{
IncludeDeleted: includeDeleted,
}
channels, appErr := a.api.channelService.GetChannelsForTeamForUser(teamID, userID, opts)
return channels, normalizeAppErr(appErr)
}
//
// Post service.
//
func (a *serviceAPIAdapter) CreatePost(post *mm_model.Post) (*mm_model.Post, error) {
post, appErr := a.api.postService.CreatePost(a.ctx, post)
return post, normalizeAppErr(appErr)
}
//
// User service.
//
func (a *serviceAPIAdapter) GetUserByID(userID string) (*mm_model.User, error) {
user, appErr := a.api.userService.GetUser(userID)
return user, normalizeAppErr(appErr)
}
func (a *serviceAPIAdapter) GetUserByUsername(name string) (*mm_model.User, error) {
user, appErr := a.api.userService.GetUserByUsername(name)
return user, normalizeAppErr(appErr)
}
func (a *serviceAPIAdapter) GetUserByEmail(email string) (*mm_model.User, error) {
user, appErr := a.api.userService.GetUserByEmail(email)
return user, normalizeAppErr(appErr)
}
func (a *serviceAPIAdapter) UpdateUser(user *mm_model.User) (*mm_model.User, error) {
user, appErr := a.api.userService.UpdateUser(user, true)
return user, normalizeAppErr(appErr)
}
func (a *serviceAPIAdapter) GetUsersFromProfiles(options *mm_model.UserGetOptions) ([]*mm_model.User, error) {
user, appErr := a.api.userService.GetUsersFromProfiles(options)
return user, normalizeAppErr(appErr)
}
//
// Team service.
//
func (a *serviceAPIAdapter) GetTeamMember(teamID string, userID string) (*mm_model.TeamMember, error) {
member, appErr := a.api.teamService.GetMember(teamID, userID)
return member, normalizeAppErr(appErr)
}
func (a *serviceAPIAdapter) CreateMember(teamID string, userID string) (*mm_model.TeamMember, error) {
member, appErr := a.api.teamService.CreateMember(a.ctx, teamID, userID)
return member, normalizeAppErr(appErr)
}
//
// Permissions service.
//
func (a *serviceAPIAdapter) HasPermissionToTeam(userID, teamID string, permission *mm_model.Permission) bool {
return a.api.permissionsService.HasPermissionToTeam(userID, teamID, permission)
}
func (a *serviceAPIAdapter) HasPermissionToChannel(askingUserID string, channelID string, permission *mm_model.Permission) bool {
return a.api.permissionsService.HasPermissionToChannel(askingUserID, channelID, permission)
}
//
// Bot service.
//
func (a *serviceAPIAdapter) EnsureBot(bot *mm_model.Bot) (string, error) {
return a.api.botService.EnsureBot(a.ctx, boardsProductID, bot)
}
//
// License service.
//
func (a *serviceAPIAdapter) GetLicense() *mm_model.License {
return a.api.licenseService.GetLicense()
}
//
// FileInfoStore service.
//
func (a *serviceAPIAdapter) GetFileInfo(fileID string) (*mm_model.FileInfo, error) {
fi, appErr := a.api.fileInfoStoreService.GetFileInfo(fileID)
return fi, normalizeAppErr(appErr)
}
//
// Cluster store.
//
func (a *serviceAPIAdapter) PublishWebSocketEvent(event string, payload map[string]interface{}, broadcast *mm_model.WebsocketBroadcast) {
a.api.clusterService.PublishWebSocketEvent(boardsProductID, event, payload, broadcast)
}
func (a *serviceAPIAdapter) PublishPluginClusterEvent(ev mm_model.PluginClusterEvent, opts mm_model.PluginClusterEventSendOptions) error {
return a.api.clusterService.PublishPluginClusterEvent(boardsProductID, ev, opts)
}
//
// Cloud service.
//
func (a *serviceAPIAdapter) GetCloudLimits() (*mm_model.ProductLimits, error) {
return a.api.cloudService.GetCloudLimits()
}
//
// Config service.
//
func (a *serviceAPIAdapter) GetConfig() *mm_model.Config {
return a.api.configService.Config()
}
//
// Logger service.
//
func (a *serviceAPIAdapter) GetLogger() mlog.LoggerIFace {
return a.api.logger
}
//
// KVStore service.
//
func (a *serviceAPIAdapter) KVSetWithOptions(key string, value []byte, options mm_model.PluginKVSetOptions) (bool, error) {
b, appErr := a.api.kvStoreService.SetPluginKeyWithOptions(boardsProductID, key, value, options)
return b, normalizeAppErr(appErr)
}
//
// Store service.
//
func (a *serviceAPIAdapter) GetMasterDB() (*sql.DB, error) {
return a.api.storeService.GetMasterDB(), nil
}
//
// System service.
//
func (a *serviceAPIAdapter) GetDiagnosticID() string {
return a.api.systemService.GetDiagnosticId()
}
// Ensure the adapter implements ServicesAPI.
var _ model.ServicesAPI = &serviceAPIAdapter{}

View File

@ -0,0 +1,287 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package product
import (
"errors"
"fmt"
"github.com/mattermost/focalboard/mattermost-plugin/server/boards"
"github.com/mattermost/mattermost-server/v6/app"
mm_model "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/plugin"
"github.com/mattermost/mattermost-server/v6/product"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
)
const (
boardsProductName = "boards"
boardsProductID = "com.mattermost.boards"
)
var errServiceTypeAssert = errors.New("type assertion failed")
func init() {
app.RegisterProduct("boards", app.ProductManifest{
Initializer: newBoardsProduct,
Dependencies: map[app.ServiceKey]struct{}{
app.TeamKey: {},
app.ChannelKey: {},
app.UserKey: {},
app.PostKey: {},
app.BotKey: {},
app.ClusterKey: {},
app.ConfigKey: {},
app.LogKey: {},
app.LicenseKey: {},
app.FilestoreKey: {},
app.FileInfoStoreKey: {},
app.RouterKey: {},
app.CloudKey: {},
app.KVStoreKey: {},
app.StoreKey: {},
app.SystemKey: {},
},
})
}
type boardsProduct struct {
teamService product.TeamService
channelService product.ChannelService
userService product.UserService
postService product.PostService
permissionsService product.PermissionService
botService product.BotService
clusterService product.ClusterService
configService product.ConfigService
logger mlog.LoggerIFace
licenseService product.LicenseService
filestoreService product.FilestoreService
fileInfoStoreService product.FileInfoStoreService
routerService product.RouterService
cloudService product.CloudService
kvStoreService product.KVStoreService
storeService product.StoreService
systemService product.SystemService
boardsApp *boards.BoardsApp
}
//nolint:gocyclo
func newBoardsProduct(mmServer *app.Server, services map[app.ServiceKey]interface{}) (app.Product, error) {
boards := &boardsProduct{}
for key, service := range services {
switch key {
case app.TeamKey:
teamService, ok := service.(product.TeamService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.teamService = teamService
case app.ChannelKey:
channelService, ok := service.(product.ChannelService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.channelService = channelService
case app.UserKey:
userService, ok := service.(product.UserService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.userService = userService
case app.PostKey:
postService, ok := service.(product.PostService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.postService = postService
case app.PermissionsKey:
permissionsService, ok := service.(product.PermissionService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.permissionsService = permissionsService
case app.BotKey:
botService, ok := service.(product.BotService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.botService = botService
case app.ClusterKey:
clusterService, ok := service.(product.ClusterService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.clusterService = clusterService
case app.ConfigKey:
configService, ok := service.(product.ConfigService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.configService = configService
case app.LogKey:
logger, ok := service.(mlog.LoggerIFace)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.logger = logger.With(mlog.String("product", boardsProductName))
case app.LicenseKey:
licenseService, ok := service.(product.LicenseService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.licenseService = licenseService
case app.FilestoreKey:
filestoreService, ok := service.(product.FilestoreService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.filestoreService = filestoreService
case app.FileInfoStoreKey:
fileInfoStoreService, ok := service.(product.FileInfoStoreService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.fileInfoStoreService = fileInfoStoreService
case app.RouterKey:
routerService, ok := service.(product.RouterService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.routerService = routerService
case app.CloudKey:
cloudService, ok := service.(product.CloudService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.cloudService = cloudService
case app.KVStoreKey:
kvStoreService, ok := service.(product.KVStoreService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.kvStoreService = kvStoreService
case app.StoreKey:
storeService, ok := service.(product.StoreService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.storeService = storeService
case app.SystemKey:
systemService, ok := service.(product.SystemService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.systemService = systemService
case app.HooksKey: // not needed
}
}
return boards, nil
}
func (bp *boardsProduct) Start() error {
if !bp.configService.Config().FeatureFlags.BoardsProduct {
bp.logger.Info("Boards product disabled via feature flag")
return nil
}
bp.logger.Info("Starting boards service")
adapter := newServiceAPIAdapter(bp)
boardsApp, err := boards.NewBoardsApp(adapter)
if err != nil {
return fmt.Errorf("failed to create Boards service: %w", err)
}
bp.boardsApp = boardsApp
if err := bp.boardsApp.Start(); err != nil {
return fmt.Errorf("failed to start Boards service: %w", err)
}
return nil
}
func (bp *boardsProduct) Stop() error {
bp.logger.Info("Stopping boards service")
if bp.boardsApp == nil {
return nil
}
if err := bp.boardsApp.Stop(); err != nil {
return fmt.Errorf("error while stopping Boards service: %w", err)
}
return nil
}
//
// These callbacks are called by the suite automatically
//
func (bp *boardsProduct) OnConfigurationChange() error {
if bp.boardsApp == nil {
return nil
}
return bp.boardsApp.OnConfigurationChange()
}
func (bp *boardsProduct) OnWebSocketConnect(webConnID, userID string) {
if bp.boardsApp == nil {
return
}
bp.boardsApp.OnWebSocketConnect(webConnID, userID)
}
func (bp *boardsProduct) OnWebSocketDisconnect(webConnID, userID string) {
if bp.boardsApp == nil {
return
}
bp.boardsApp.OnWebSocketDisconnect(webConnID, userID)
}
func (bp *boardsProduct) WebSocketMessageHasBeenPosted(webConnID, userID string, req *mm_model.WebSocketRequest) {
if bp.boardsApp == nil {
return
}
bp.boardsApp.WebSocketMessageHasBeenPosted(webConnID, userID, req)
}
func (bp *boardsProduct) OnPluginClusterEvent(ctx *plugin.Context, ev mm_model.PluginClusterEvent) {
if bp.boardsApp == nil {
return
}
bp.boardsApp.OnPluginClusterEvent(ctx, ev)
}
func (bp *boardsProduct) MessageWillBePosted(ctx *plugin.Context, post *mm_model.Post) (*mm_model.Post, string) {
if bp.boardsApp == nil {
return post, ""
}
return bp.boardsApp.MessageWillBePosted(ctx, post)
}
func (bp *boardsProduct) MessageWillBeUpdated(ctx *plugin.Context, newPost, oldPost *mm_model.Post) (*mm_model.Post, string) {
if bp.boardsApp == nil {
return newPost, ""
}
return bp.boardsApp.MessageWillBeUpdated(ctx, newPost, oldPost)
}
func (bp *boardsProduct) OnCloudLimitsUpdated(limits *mm_model.ProductLimits) {
if bp.boardsApp == nil {
return
}
bp.boardsApp.OnCloudLimitsUpdated(limits)
}
func (bp *boardsProduct) RunDataRetention(nowTime, batchSize int64) (int64, error) {
if bp.boardsApp == nil {
return 0, nil
}
return bp.boardsApp.RunDataRetention(nowTime, batchSize)
}

View File

@ -1,113 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package product
import (
"errors"
"fmt"
"github.com/mattermost/mattermost-server/v6/app"
"github.com/mattermost/mattermost-server/v6/product"
)
var errServiceTypeAssert = errors.New("type assertion failed")
func init() {
app.RegisterProduct("boards", app.ProductManifest{
Initializer: newBoards,
Dependencies: map[app.ServiceKey]struct{}{},
})
}
type Boards struct {
teamService product.TeamService
channelService product.ChannelService
userService product.UserService
postService product.PostService
botService product.BotService
clusterService product.ClusterService
// configService product.ConfigService
logService product.LogService
licenseService product.LicenseService
// filestoreService product.FilestoreService
routerService product.RouterService
}
func newBoards(mmServer *app.Server, services map[app.ServiceKey]interface{}) (app.Product, error) {
boards := &Boards{}
for key, service := range services {
switch key {
case app.TeamKey:
teamService, ok := service.(product.TeamService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.teamService = teamService
case app.ChannelKey:
channelService, ok := service.(product.ChannelService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.channelService = channelService
case app.UserKey:
userService, ok := service.(product.UserService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.userService = userService
case app.PostKey:
postService, ok := service.(product.PostService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.postService = postService
case app.BotKey:
botService, ok := service.(product.BotService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.botService = botService
case app.ClusterKey:
clusterService, ok := service.(product.ClusterService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.clusterService = clusterService
case app.ConfigKey:
// TODO
case app.LogKey:
logService, ok := service.(product.LogService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.logService = logService
case app.LicenseKey:
licenseService, ok := service.(product.LicenseService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.licenseService = licenseService
case app.FilestoreKey:
// TODO
case app.RouterKey:
routerService, ok := service.(product.RouterService)
if !ok {
return nil, fmt.Errorf("invalid service key '%s': %w", key, errServiceTypeAssert)
}
boards.routerService = routerService
case app.HooksKey, app.PermissionsKey:
// not needed
}
}
return boards, nil
}
func (b *Boards) Start() error {
return nil
}
func (b *Boards) Stop() error {
return nil
}

View File

@ -0,0 +1,212 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package main
import (
"database/sql"
"github.com/mattermost/focalboard/server/model"
"github.com/mattermost/mattermost-server/v6/plugin"
mm_model "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
)
type storeService interface {
GetMasterDB() (*sql.DB, error)
}
// normalizeAppError returns a truly nil error if appErr is nil
// See https://golang.org/doc/faq#nil_error for more details.
func normalizeAppErr(appErr *mm_model.AppError) error {
if appErr == nil {
return nil
}
return appErr
}
// pluginAPIAdapter is an adapter that ensures all Plugin API methods have the same signature as the
// services API.
// Note: this will be removed when plugin builds are no longer needed.
type pluginAPIAdapter struct {
api plugin.API
storeService storeService
logger mlog.LoggerIFace
}
func newServiceAPIAdapter(api plugin.API, storeService storeService, logger mlog.LoggerIFace) *pluginAPIAdapter {
return &pluginAPIAdapter{
api: api,
storeService: storeService,
logger: logger,
}
}
//
// Channels service.
//
func (a *pluginAPIAdapter) GetDirectChannel(userID1, userID2 string) (*mm_model.Channel, error) {
channel, appErr := a.api.GetDirectChannel(userID1, userID2)
return channel, normalizeAppErr(appErr)
}
func (a *pluginAPIAdapter) GetChannelByID(channelID string) (*mm_model.Channel, error) {
channel, appErr := a.api.GetChannel(channelID)
return channel, normalizeAppErr(appErr)
}
func (a *pluginAPIAdapter) GetChannelMember(channelID string, userID string) (*mm_model.ChannelMember, error) {
member, appErr := a.api.GetChannelMember(channelID, userID)
return member, normalizeAppErr(appErr)
}
func (a *pluginAPIAdapter) GetChannelsForTeamForUser(teamID string, userID string, includeDeleted bool) (mm_model.ChannelList, error) {
channels, appErr := a.api.GetChannelsForTeamForUser(teamID, userID, includeDeleted)
return channels, normalizeAppErr(appErr)
}
//
// Post service.
//
func (a *pluginAPIAdapter) CreatePost(post *mm_model.Post) (*mm_model.Post, error) {
post, appErr := a.api.CreatePost(post)
return post, normalizeAppErr(appErr)
}
//
// User service.
//
func (a *pluginAPIAdapter) GetUserByID(userID string) (*mm_model.User, error) {
user, appErr := a.api.GetUser(userID)
return user, normalizeAppErr(appErr)
}
func (a *pluginAPIAdapter) GetUserByUsername(name string) (*mm_model.User, error) {
user, appErr := a.api.GetUserByUsername(name)
return user, normalizeAppErr(appErr)
}
func (a *pluginAPIAdapter) GetUserByEmail(email string) (*mm_model.User, error) {
user, appErr := a.api.GetUserByEmail(email)
return user, normalizeAppErr(appErr)
}
func (a *pluginAPIAdapter) UpdateUser(user *mm_model.User) (*mm_model.User, error) {
user, appErr := a.api.UpdateUser(user)
return user, normalizeAppErr(appErr)
}
func (a *pluginAPIAdapter) GetUsersFromProfiles(options *mm_model.UserGetOptions) ([]*mm_model.User, error) {
users, appErr := a.api.GetUsers(options)
return users, normalizeAppErr(appErr)
}
//
// Team service.
//
func (a *pluginAPIAdapter) GetTeamMember(teamID string, userID string) (*mm_model.TeamMember, error) {
member, appErr := a.api.GetTeamMember(teamID, userID)
return member, normalizeAppErr(appErr)
}
func (a *pluginAPIAdapter) CreateMember(teamID string, userID string) (*mm_model.TeamMember, error) {
member, appErr := a.api.CreateTeamMember(teamID, userID)
return member, normalizeAppErr(appErr)
}
//
// Permissions service.
//
func (a *pluginAPIAdapter) HasPermissionToTeam(userID, teamID string, permission *mm_model.Permission) bool {
return a.api.HasPermissionToTeam(userID, teamID, permission)
}
func (a *pluginAPIAdapter) HasPermissionToChannel(askingUserID string, channelID string, permission *mm_model.Permission) bool {
return a.api.HasPermissionToChannel(askingUserID, channelID, permission)
}
//
// Bot service.
//
func (a *pluginAPIAdapter) EnsureBot(bot *mm_model.Bot) (string, error) {
return a.api.EnsureBotUser(bot)
}
//
// License service.
//
func (a *pluginAPIAdapter) GetLicense() *mm_model.License {
return a.api.GetLicense()
}
//
// FileInfoStore service.
//
func (a *pluginAPIAdapter) GetFileInfo(fileID string) (*mm_model.FileInfo, error) {
fi, appErr := a.api.GetFileInfo(fileID)
return fi, normalizeAppErr(appErr)
}
//
// Cluster store.
//
func (a *pluginAPIAdapter) PublishWebSocketEvent(event string, payload map[string]interface{}, broadcast *mm_model.WebsocketBroadcast) {
a.api.PublishWebSocketEvent(event, payload, broadcast)
}
func (a *pluginAPIAdapter) PublishPluginClusterEvent(ev mm_model.PluginClusterEvent, opts mm_model.PluginClusterEventSendOptions) error {
return a.api.PublishPluginClusterEvent(ev, opts)
}
//
// Cloud service.
//
func (a *pluginAPIAdapter) GetCloudLimits() (*mm_model.ProductLimits, error) {
return a.api.GetCloudLimits()
}
//
// Config service.
//
func (a *pluginAPIAdapter) GetConfig() *mm_model.Config {
return a.api.GetUnsanitizedConfig()
}
//
// Logger service.
//
func (a *pluginAPIAdapter) GetLogger() mlog.LoggerIFace {
return a.logger
}
//
// KVStore service.
//
func (a *pluginAPIAdapter) KVSetWithOptions(key string, value []byte, options mm_model.PluginKVSetOptions) (bool, error) {
b, appErr := a.api.KVSetWithOptions(key, value, options)
return b, normalizeAppErr(appErr)
}
//
// Store service.
//
func (a *pluginAPIAdapter) GetMasterDB() (*sql.DB, error) {
return a.storeService.GetMasterDB()
}
//
// System service.
//
func (a *pluginAPIAdapter) GetDiagnosticID() string {
return a.api.GetDiagnosticId()
}
// Ensure the adapter implements ServicesAPI.
var _ model.ServicesAPI = &pluginAPIAdapter{}

View File

@ -0,0 +1,218 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package boards
import (
"fmt"
"net/http"
"sync"
"github.com/mattermost/focalboard/server/auth"
"github.com/mattermost/focalboard/server/model"
"github.com/mattermost/focalboard/server/server"
"github.com/mattermost/focalboard/server/services/notify"
"github.com/mattermost/focalboard/server/services/permissions/mmpermissions"
"github.com/mattermost/focalboard/server/services/store"
"github.com/mattermost/focalboard/server/services/store/mattermostauthlayer"
"github.com/mattermost/focalboard/server/services/store/sqlstore"
"github.com/mattermost/focalboard/server/utils"
"github.com/mattermost/focalboard/server/ws"
mm_model "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/plugin"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
"github.com/mattermost/mattermost-plugin-api/cluster"
)
const (
boardsFeatureFlagName = "BoardsFeatureFlags"
PluginName = "focalboard"
SharedBoardsName = "enablepublicsharedboards"
notifyFreqCardSecondsKey = "notify_freq_card_seconds"
notifyFreqBoardSecondsKey = "notify_freq_board_seconds"
)
type BoardsEmbed struct {
OriginalPath string `json:"originalPath"`
TeamID string `json:"teamID"`
ViewID string `json:"viewID"`
BoardID string `json:"boardID"`
CardID string `json:"cardID"`
ReadToken string `json:"readToken,omitempty"`
}
type BoardsApp struct {
// configurationLock synchronizes access to the configuration.
configurationLock sync.RWMutex
// configuration is the active plugin configuration. Consult getConfiguration and
// setConfiguration for usage.
configuration *configuration
server *server.Server
wsPluginAdapter ws.PluginAdapterInterface
servicesAPI model.ServicesAPI
logger mlog.LoggerIFace
}
func NewBoardsApp(api model.ServicesAPI) (*BoardsApp, error) {
mmconfig := api.GetConfig()
logger := api.GetLogger()
baseURL := ""
if mmconfig.ServiceSettings.SiteURL != nil {
baseURL = *mmconfig.ServiceSettings.SiteURL
}
serverID := api.GetDiagnosticID()
cfg := createBoardsConfig(*mmconfig, baseURL, serverID)
sqlDB, err := api.GetMasterDB()
if err != nil {
return nil, fmt.Errorf("cannot access database while initializing Boards: %w", err)
}
storeParams := sqlstore.Params{
DBType: cfg.DBType,
ConnectionString: cfg.DBConfigString,
TablePrefix: cfg.DBTablePrefix,
Logger: logger,
DB: sqlDB,
IsPlugin: true,
NewMutexFn: func(name string) (*cluster.Mutex, error) {
return cluster.NewMutex(&mutexAPIAdapter{api: api}, name)
},
ServicesAPI: api,
}
var db store.Store
db, err = sqlstore.New(storeParams)
if err != nil {
return nil, fmt.Errorf("error initializing the DB: %w", err)
}
if cfg.AuthMode == server.MattermostAuthMod {
layeredStore, err2 := mattermostauthlayer.New(cfg.DBType, sqlDB, db, logger, api, storeParams.TablePrefix)
if err2 != nil {
return nil, fmt.Errorf("error initializing the DB: %w", err2)
}
db = layeredStore
}
permissionsService := mmpermissions.New(db, api, logger)
wsPluginAdapter := ws.NewPluginAdapter(api, auth.New(cfg, db, permissionsService), db, logger)
backendParams := notifyBackendParams{
cfg: cfg,
servicesAPI: api,
appAPI: &appAPI{store: db},
permissions: permissionsService,
serverRoot: baseURL + "/boards",
logger: logger,
}
var notifyBackends []notify.Backend
mentionsBackend, err := createMentionsNotifyBackend(backendParams)
if err != nil {
return nil, fmt.Errorf("error creating mention notifications backend: %w", err)
}
notifyBackends = append(notifyBackends, mentionsBackend)
subscriptionsBackend, err2 := createSubscriptionsNotifyBackend(backendParams)
if err2 != nil {
return nil, fmt.Errorf("error creating subscription notifications backend: %w", err2)
}
notifyBackends = append(notifyBackends, subscriptionsBackend)
mentionsBackend.AddListener(subscriptionsBackend)
params := server.Params{
Cfg: cfg,
SingleUserToken: "",
DBStore: db,
Logger: logger,
ServerID: serverID,
WSAdapter: wsPluginAdapter,
NotifyBackends: notifyBackends,
PermissionsService: permissionsService,
IsPlugin: true,
}
server, err := server.New(params)
if err != nil {
return nil, fmt.Errorf("error initializing the server: %w", err)
}
backendParams.appAPI.init(db, server.App())
if utils.IsCloudLicense(api.GetLicense()) {
limits, err := api.GetCloudLimits()
if err != nil {
return nil, fmt.Errorf("error fetching cloud limits when starting Boards: %w", err)
}
if err := server.App().SetCloudLimits(limits); err != nil {
return nil, fmt.Errorf("error setting cloud limits when starting Boards: %w", err)
}
}
return &BoardsApp{
server: server,
wsPluginAdapter: wsPluginAdapter,
servicesAPI: api,
logger: logger,
}, nil
}
func (b *BoardsApp) Start() error {
if err := b.server.Start(); err != nil {
return fmt.Errorf("error starting Boards server: %w", err)
}
return nil
}
func (b *BoardsApp) Stop() error {
return b.server.Shutdown()
}
//
// These callbacks are called automatically by the suite server.
//
func (b *BoardsApp) MessageWillBePosted(_ *plugin.Context, post *mm_model.Post) (*mm_model.Post, string) {
return postWithBoardsEmbed(post), ""
}
func (b *BoardsApp) MessageWillBeUpdated(_ *plugin.Context, newPost, _ *mm_model.Post) (*mm_model.Post, string) {
return postWithBoardsEmbed(newPost), ""
}
func (b *BoardsApp) OnWebSocketConnect(webConnID, userID string) {
b.wsPluginAdapter.OnWebSocketConnect(webConnID, userID)
}
func (b *BoardsApp) OnWebSocketDisconnect(webConnID, userID string) {
b.wsPluginAdapter.OnWebSocketDisconnect(webConnID, userID)
}
func (b *BoardsApp) WebSocketMessageHasBeenPosted(webConnID, userID string, req *mm_model.WebSocketRequest) {
b.wsPluginAdapter.WebSocketMessageHasBeenPosted(webConnID, userID, req)
}
func (b *BoardsApp) OnPluginClusterEvent(_ *plugin.Context, ev mm_model.PluginClusterEvent) {
b.wsPluginAdapter.HandleClusterEvent(ev)
}
func (b *BoardsApp) OnCloudLimitsUpdated(limits *mm_model.ProductLimits) {
if err := b.server.App().SetCloudLimits(limits); err != nil {
b.logger.Error("Error setting the cloud limits for Boards", mlog.Err(err))
}
}
// ServeHTTP demonstrates a plugin that handles HTTP requests by greeting the world.
func (b *BoardsApp) ServeHTTP(_ *plugin.Context, w http.ResponseWriter, r *http.Request) {
router := b.server.GetRootRouter()
router.ServeHTTP(w, r)
}

View File

@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package main
package boards
import (
"io/ioutil"
@ -9,40 +9,13 @@ import (
"net/http/httptest"
"testing"
"github.com/mattermost/mattermost-server/v6/model"
"github.com/stretchr/testify/assert"
"github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
)
func TestServeHTTP(t *testing.T) {
th, tearDown := SetupTestHelper(t)
defer tearDown()
assert := assert.New(t)
plugin := Plugin{
server: th.Server,
}
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/hello", nil)
plugin.ServeHTTP(nil, w, r)
result := w.Result()
assert.NotNil(result)
defer result.Body.Close()
bodyBytes, err := ioutil.ReadAll(result.Body)
assert.Nil(err)
bodyString := string(bodyBytes)
assert.Equal("Hello", bodyString)
}
func TestSetConfiguration(t *testing.T) {
th, tearDown := SetupTestHelper(t)
defer tearDown()
plugin := Plugin{
server: th.Server,
}
boolTrue := true
stringRef := ""
@ -89,7 +62,7 @@ func TestSetConfiguration(t *testing.T) {
mmConfig := baseConfig
mmConfig.LogSettings = *logSettings
config := plugin.createBoardsConfig(*mmConfig, "", "testId")
config := createBoardsConfig(*mmConfig, "", "testId")
assert.Equal(t, true, config.Telemetry)
assert.Equal(t, "testId", config.TelemetryID)
})
@ -97,9 +70,9 @@ func TestSetConfiguration(t *testing.T) {
t.Run("test enable shared boards", func(t *testing.T) {
mmConfig := baseConfig
mmConfig.PluginSettings.Plugins = make(map[string]map[string]interface{})
mmConfig.PluginSettings.Plugins[pluginName] = make(map[string]interface{})
mmConfig.PluginSettings.Plugins[pluginName][sharedBoardsName] = true
config := plugin.createBoardsConfig(*mmConfig, "", "")
mmConfig.PluginSettings.Plugins[PluginName] = make(map[string]interface{})
mmConfig.PluginSettings.Plugins[PluginName][SharedBoardsName] = true
config := createBoardsConfig(*mmConfig, "", "")
assert.Equal(t, true, config.EnablePublicSharedBoards)
})
@ -113,7 +86,7 @@ func TestSetConfiguration(t *testing.T) {
mmConfig := baseConfig
mmConfig.FeatureFlags = featureFlags
config := plugin.createBoardsConfig(*mmConfig, "", "")
config := createBoardsConfig(*mmConfig, "", "")
assert.Equal(t, "true", config.FeatureFlags["TestBoolFeature"])
assert.Equal(t, "test", config.FeatureFlags["TestFeature"])
@ -121,3 +94,28 @@ func TestSetConfiguration(t *testing.T) {
assert.Equal(t, "true", config.FeatureFlags["myTest"])
})
}
func TestServeHTTP(t *testing.T) {
th, tearDown := SetupTestHelper(t)
defer tearDown()
b := &BoardsApp{
server: th.Server,
logger: mlog.CreateConsoleTestLogger(true, mlog.LvlError),
}
assert := assert.New(t)
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/hello", nil)
b.ServeHTTP(nil, w, r)
result := w.Result()
assert.NotNil(result)
defer result.Body.Close()
bodyBytes, err := ioutil.ReadAll(result.Body)
assert.Nil(err)
bodyString := string(bodyBytes)
assert.Equal("Hello", bodyString)
}

View File

@ -0,0 +1,136 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package boards
import (
"math"
"path"
"strings"
"github.com/mattermost/focalboard/server/services/config"
mm_model "github.com/mattermost/mattermost-server/v6/model"
)
func createBoardsConfig(mmconfig mm_model.Config, baseURL string, serverID string) *config.Configuration {
filesS3Config := config.AmazonS3Config{}
if mmconfig.FileSettings.AmazonS3AccessKeyId != nil {
filesS3Config.AccessKeyID = *mmconfig.FileSettings.AmazonS3AccessKeyId
}
if mmconfig.FileSettings.AmazonS3SecretAccessKey != nil {
filesS3Config.SecretAccessKey = *mmconfig.FileSettings.AmazonS3SecretAccessKey
}
if mmconfig.FileSettings.AmazonS3Bucket != nil {
filesS3Config.Bucket = *mmconfig.FileSettings.AmazonS3Bucket
}
if mmconfig.FileSettings.AmazonS3PathPrefix != nil {
filesS3Config.PathPrefix = *mmconfig.FileSettings.AmazonS3PathPrefix
}
if mmconfig.FileSettings.AmazonS3Region != nil {
filesS3Config.Region = *mmconfig.FileSettings.AmazonS3Region
}
if mmconfig.FileSettings.AmazonS3Endpoint != nil {
filesS3Config.Endpoint = *mmconfig.FileSettings.AmazonS3Endpoint
}
if mmconfig.FileSettings.AmazonS3SSL != nil {
filesS3Config.SSL = *mmconfig.FileSettings.AmazonS3SSL
}
if mmconfig.FileSettings.AmazonS3SignV2 != nil {
filesS3Config.SignV2 = *mmconfig.FileSettings.AmazonS3SignV2
}
if mmconfig.FileSettings.AmazonS3SSE != nil {
filesS3Config.SSE = *mmconfig.FileSettings.AmazonS3SSE
}
if mmconfig.FileSettings.AmazonS3Trace != nil {
filesS3Config.Trace = *mmconfig.FileSettings.AmazonS3Trace
}
enableTelemetry := false
if mmconfig.LogSettings.EnableDiagnostics != nil {
enableTelemetry = *mmconfig.LogSettings.EnableDiagnostics
}
enablePublicSharedBoards := false
if mmconfig.PluginSettings.Plugins[PluginName][SharedBoardsName] == true {
enablePublicSharedBoards = true
}
enableBoardsDeletion := false
if mmconfig.DataRetentionSettings.EnableBoardsDeletion != nil {
enableBoardsDeletion = true
}
featureFlags := parseFeatureFlags(mmconfig.FeatureFlags.ToMap())
return &config.Configuration{
ServerRoot: baseURL + "/plugins/focalboard",
Port: -1,
DBType: *mmconfig.SqlSettings.DriverName,
DBConfigString: *mmconfig.SqlSettings.DataSource,
DBTablePrefix: "focalboard_",
UseSSL: false,
SecureCookie: true,
WebPath: path.Join(*mmconfig.PluginSettings.Directory, "focalboard", "pack"),
FilesDriver: *mmconfig.FileSettings.DriverName,
FilesPath: *mmconfig.FileSettings.Directory,
FilesS3Config: filesS3Config,
MaxFileSize: *mmconfig.FileSettings.MaxFileSize,
Telemetry: enableTelemetry,
TelemetryID: serverID,
WebhookUpdate: []string{},
SessionExpireTime: 2592000,
SessionRefreshTime: 18000,
LocalOnly: false,
EnableLocalMode: false,
LocalModeSocketLocation: "",
AuthMode: "mattermost",
EnablePublicSharedBoards: enablePublicSharedBoards,
FeatureFlags: featureFlags,
NotifyFreqCardSeconds: getPluginSettingInt(mmconfig, notifyFreqCardSecondsKey, 120),
NotifyFreqBoardSeconds: getPluginSettingInt(mmconfig, notifyFreqBoardSecondsKey, 86400),
EnableDataRetention: enableBoardsDeletion,
DataRetentionDays: *mmconfig.DataRetentionSettings.BoardsRetentionDays,
TeammateNameDisplay: *mmconfig.TeamSettings.TeammateNameDisplay,
}
}
func getPluginSetting(mmConfig mm_model.Config, key string) (interface{}, bool) {
plugin, ok := mmConfig.PluginSettings.Plugins[PluginName]
if !ok {
return nil, false
}
val, ok := plugin[key]
if !ok {
return nil, false
}
return val, true
}
func getPluginSettingInt(mmConfig mm_model.Config, key string, def int) int {
val, ok := getPluginSetting(mmConfig, key)
if !ok {
return def
}
valFloat, ok := val.(float64)
if !ok {
return def
}
return int(math.Round(valFloat))
}
func parseFeatureFlags(configFeatureFlags map[string]string) map[string]string {
featureFlags := make(map[string]string)
for key, value := range configFeatureFlags {
// Break out FeatureFlags and pass remaining
if key == boardsFeatureFlagName {
for _, flag := range strings.Split(value, "-") {
featureFlags[flag] = "true"
}
} else {
featureFlags[key] = value
}
}
return featureFlags
}

View File

@ -1,4 +1,4 @@
package main
package boards
import (
"reflect"
@ -29,15 +29,15 @@ func (c *configuration) Clone() *configuration {
// getConfiguration retrieves the active configuration under lock, making it safe to use
// concurrently. The active configuration may change underneath the client of this method, but
// the struct returned by this API call is considered immutable.
func (p *Plugin) getConfiguration() *configuration {
p.configurationLock.RLock()
defer p.configurationLock.RUnlock()
func (b *BoardsApp) getConfiguration() *configuration {
b.configurationLock.RLock()
defer b.configurationLock.RUnlock()
if p.configuration == nil {
if b.configuration == nil {
return &configuration{}
}
return p.configuration
return b.configuration
}
// setConfiguration replaces the active configuration under lock.
@ -49,11 +49,11 @@ func (p *Plugin) getConfiguration() *configuration {
// This method panics if setConfiguration is called with the existing configuration. This almost
// certainly means that the configuration was modified without being cloned and may result in
// an unsafe access.
func (p *Plugin) setConfiguration(configuration *configuration) {
p.configurationLock.Lock()
defer p.configurationLock.Unlock()
func (b *BoardsApp) setConfiguration(configuration *configuration) {
b.configurationLock.Lock()
defer b.configurationLock.Unlock()
if configuration != nil && p.configuration == configuration {
if configuration != nil && b.configuration == configuration {
// Ignore assignment if the configuration struct is empty. Go will optimize the
// allocation for same to point at the same memory address, breaking the check
// above.
@ -64,41 +64,41 @@ func (p *Plugin) setConfiguration(configuration *configuration) {
panic("setConfiguration called with the existing configuration")
}
p.configuration = configuration
b.configuration = configuration
}
// OnConfigurationChange is invoked when configuration changes may have been made.
func (p *Plugin) OnConfigurationChange() error {
func (b *BoardsApp) OnConfigurationChange() error {
// Have we been setup by OnActivate?
if p.wsPluginAdapter == nil {
if b.server == nil {
return nil
}
mmconfig := p.API.GetConfig()
mmconfig := b.servicesAPI.GetConfig()
// handle plugin configuration settings
enableShareBoards := false
if mmconfig.PluginSettings.Plugins[pluginName][sharedBoardsName] == true {
if mmconfig.PluginSettings.Plugins[PluginName][SharedBoardsName] == true {
enableShareBoards = true
}
configuration := &configuration{
EnablePublicSharedBoards: enableShareBoards,
}
p.setConfiguration(configuration)
p.server.Config().EnablePublicSharedBoards = enableShareBoards
b.setConfiguration(configuration)
b.server.Config().EnablePublicSharedBoards = enableShareBoards
// handle feature flags
p.server.Config().FeatureFlags = parseFeatureFlags(mmconfig.FeatureFlags.ToMap())
b.server.Config().FeatureFlags = parseFeatureFlags(mmconfig.FeatureFlags.ToMap())
// handle Data Retention settings
enableBoardsDeletion := false
if mmconfig.DataRetentionSettings.EnableBoardsDeletion != nil {
enableBoardsDeletion = true
}
p.server.Config().EnableDataRetention = enableBoardsDeletion
p.server.Config().DataRetentionDays = *mmconfig.DataRetentionSettings.BoardsRetentionDays
p.server.Config().TeammateNameDisplay = *mmconfig.TeamSettings.TeammateNameDisplay
b.server.Config().EnableDataRetention = enableBoardsDeletion
b.server.Config().DataRetentionDays = *mmconfig.DataRetentionSettings.BoardsRetentionDays
b.server.Config().TeammateNameDisplay = *mmconfig.TeamSettings.TeammateNameDisplay
p.server.UpdateAppConfig()
p.wsPluginAdapter.BroadcastConfigChange(*p.server.App().GetClientConfig())
b.server.UpdateAppConfig()
b.wsPluginAdapter.BroadcastConfigChange(*b.server.App().GetClientConfig())
return nil
}

View File

@ -1,18 +1,21 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package main
package boards
import (
"testing"
"github.com/golang/mock/gomock"
"github.com/mattermost/focalboard/server/integrationtests"
"github.com/mattermost/focalboard/server/model"
"github.com/mattermost/focalboard/server/server"
"github.com/mattermost/focalboard/server/ws"
mockservicesapi "github.com/mattermost/focalboard/server/model/mocks"
serverModel "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/plugin/plugintest"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -40,16 +43,16 @@ func newTestServer() *server.Server {
return integrationtests.NewTestServerPluginMode()
}
func TestConfigurationNullConfiguration(t *testing.T) {
plugin := &Plugin{}
assert.NotNil(t, plugin.getConfiguration())
boardsApp := &BoardsApp{}
assert.NotNil(t, boardsApp.getConfiguration())
}
func TestOnConfigurationChange(t *testing.T) {
stringRef := ""
basePlugins := make(map[string]map[string]interface{})
basePlugins[pluginName] = make(map[string]interface{})
basePlugins[pluginName][sharedBoardsName] = true
basePlugins[PluginName] = make(map[string]interface{})
basePlugins[PluginName][SharedBoardsName] = true
baseFeatureFlags := &serverModel.FeatureFlags{
BoardsFeatureFlags: "Feature1-Feature2",
@ -77,26 +80,29 @@ func TestOnConfigurationChange(t *testing.T) {
t.Run("Test Load Plugin Success", func(t *testing.T) {
th, tearDown := SetupTestHelper(t)
defer tearDown()
api := &plugintest.API{}
api.On("GetUnsanitizedConfig").Return(baseConfig)
api.On("GetConfig").Return(baseConfig)
p := Plugin{}
p.SetAPI(api)
p.server = th.Server
p.wsPluginAdapter = &FakePluginAdapter{}
ctrl := gomock.NewController(t)
api := mockservicesapi.NewMockServicesAPI(ctrl)
api.EXPECT().GetConfig().Return(baseConfig)
err := p.OnConfigurationChange()
b := &BoardsApp{
server: th.Server,
wsPluginAdapter: &FakePluginAdapter{},
servicesAPI: api,
logger: mlog.CreateConsoleTestLogger(true, mlog.LvlError),
}
err := b.OnConfigurationChange()
assert.NoError(t, err)
assert.Equal(t, 1, count)
// make sure both App and Server got updated
assert.True(t, p.server.Config().EnablePublicSharedBoards)
assert.True(t, p.server.App().GetClientConfig().EnablePublicSharedBoards)
assert.True(t, b.server.Config().EnablePublicSharedBoards)
assert.True(t, b.server.App().GetClientConfig().EnablePublicSharedBoards)
assert.Equal(t, "true", p.server.Config().FeatureFlags["Feature1"])
assert.Equal(t, "true", p.server.Config().FeatureFlags["Feature2"])
assert.Equal(t, "", p.server.Config().FeatureFlags["Feature3"])
assert.Equal(t, "true", b.server.Config().FeatureFlags["Feature1"])
assert.Equal(t, "true", b.server.Config().FeatureFlags["Feature2"])
assert.Equal(t, "", b.server.Config().FeatureFlags["Feature3"])
})
}

View File

@ -1,6 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package main
package boards
import (
"errors"
@ -9,17 +9,17 @@ import (
var ErrInsufficientLicense = errors.New("appropriate license required")
func (p *Plugin) RunDataRetention(nowTime, batchSize int64) (int64, error) {
p.server.Logger().Debug("Boards RunDataRetention")
license := p.server.Store().GetLicense()
func (b *BoardsApp) RunDataRetention(nowTime, batchSize int64) (int64, error) {
b.logger.Debug("Boards RunDataRetention")
license := b.server.Store().GetLicense()
if license == nil || !(*license.Features.DataRetention) {
return 0, ErrInsufficientLicense
}
if p.server.Config().EnableDataRetention {
boardsRetentionDays := p.server.Config().DataRetentionDays
if b.server.Config().EnableDataRetention {
boardsRetentionDays := b.server.Config().DataRetentionDays
endTimeBoards := convertDaysToCutoff(boardsRetentionDays, time.Unix(nowTime/1000, 0))
return p.server.Store().RunDataRetention(endTimeBoards, batchSize)
return b.server.Store().RunDataRetention(endTimeBoards, batchSize)
}
return 0, nil
}

View File

@ -1,9 +1,10 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package main
package boards
import (
"os"
"testing"
"time"
@ -12,9 +13,10 @@ import (
"github.com/mattermost/focalboard/server/services/config"
"github.com/mattermost/focalboard/server/services/permissions/localpermissions"
"github.com/mattermost/focalboard/server/services/store/mockstore"
"github.com/stretchr/testify/assert"
"github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
"github.com/stretchr/testify/assert"
)
type TestHelperMockStore struct {
@ -22,16 +24,24 @@ type TestHelperMockStore struct {
Store *mockstore.MockStore
}
func SetupTestHelperMockStore(t *testing.T) *TestHelperMockStore {
func SetupTestHelperMockStore(t *testing.T) (*TestHelperMockStore, func()) {
th := &TestHelperMockStore{}
origUnitTesting := os.Getenv("FOCALBOARD_UNIT_TESTING")
os.Setenv("FOCALBOARD_UNIT_TESTING", "1")
ctrl := gomock.NewController(t)
mockStore := mockstore.NewMockStore(ctrl)
tearDown := func() {
defer ctrl.Finish()
os.Setenv("FOCALBOARD_UNIT_TESTING", origUnitTesting)
}
th.Server = newTestServerMock(mockStore)
th.Store = mockStore
return th
return th, tearDown
}
func newTestServerMock(mockStore *mockstore.MockStore) *server.Server {
@ -66,15 +76,19 @@ func newTestServerMock(mockStore *mockstore.MockStore) *server.Server {
}
func TestRunDataRetention(t *testing.T) {
th := SetupTestHelperMockStore(t)
plugin := Plugin{}
plugin.server = th.Server
th, tearDown := SetupTestHelperMockStore(t)
defer tearDown()
b := &BoardsApp{
server: th.Server,
logger: mlog.CreateConsoleTestLogger(true, mlog.LvlError),
}
now := time.Now().UnixNano()
t.Run("test null license", func(t *testing.T) {
th.Store.EXPECT().GetLicense().Return(nil)
_, err := plugin.RunDataRetention(now, 10)
_, err := b.RunDataRetention(now, 10)
assert.NotNil(t, err)
assert.Equal(t, ErrInsufficientLicense, err)
})
@ -89,7 +103,7 @@ func TestRunDataRetention(t *testing.T) {
},
},
)
_, err := plugin.RunDataRetention(now, 10)
_, err := b.RunDataRetention(now, 10)
assert.NotNil(t, err)
assert.Equal(t, ErrInsufficientLicense, err)
})
@ -103,7 +117,7 @@ func TestRunDataRetention(t *testing.T) {
},
})
count, err := plugin.RunDataRetention(now, 10)
count, err := b.RunDataRetention(now, 10)
assert.Nil(t, err)
assert.Equal(t, int64(0), count)
})
@ -118,9 +132,9 @@ func TestRunDataRetention(t *testing.T) {
})
th.Store.EXPECT().RunDataRetention(gomock.Any(), int64(10)).Return(int64(100), nil)
plugin.server.Config().EnableDataRetention = true
b.server.Config().EnableDataRetention = true
count, err := plugin.RunDataRetention(now, 10)
count, err := b.RunDataRetention(now, 10)
assert.Nil(t, err)
assert.Equal(t, int64(100), count)

View File

@ -0,0 +1,34 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package boards
import (
"errors"
"net/http"
mm_model "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
"github.com/mattermost/focalboard/server/model"
)
type mutexAPIAdapter struct {
api model.ServicesAPI
}
func (m *mutexAPIAdapter) KVSetWithOptions(key string, value []byte, options mm_model.PluginKVSetOptions) (bool, *mm_model.AppError) {
b, err := m.api.KVSetWithOptions(key, value, options)
var appErr *mm_model.AppError
if err != nil {
if !errors.As(err, &appErr) {
appErr = mm_model.NewAppError("KVSetWithOptions", "", nil, "", http.StatusInternalServerError)
}
}
return b, appErr
}
func (m *mutexAPIAdapter) LogError(msg string, keyValuePairs ...interface{}) {
m.api.GetLogger().Error(msg, mlog.Array("kvpairs", keyValuePairs))
}

View File

@ -1,4 +1,4 @@
package main
package boards
import (
"fmt"
@ -12,8 +12,6 @@ import (
"github.com/mattermost/focalboard/server/services/permissions"
"github.com/mattermost/focalboard/server/services/store"
pluginapi "github.com/mattermost/mattermost-plugin-api"
mm_model "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
@ -27,15 +25,15 @@ const (
type notifyBackendParams struct {
cfg *config.Configuration
client *pluginapi.Client
servicesAPI model.ServicesAPI
permissions permissions.PermissionsService
appAPI *appAPI
serverRoot string
logger *mlog.Logger
logger mlog.LoggerIFace
}
func createMentionsNotifyBackend(params notifyBackendParams) (*notifymentions.Backend, error) {
delivery, err := createDelivery(params.client, params.serverRoot)
delivery, err := createDelivery(params.servicesAPI, params.serverRoot)
if err != nil {
return nil, err
}
@ -53,7 +51,7 @@ func createMentionsNotifyBackend(params notifyBackendParams) (*notifymentions.Ba
}
func createSubscriptionsNotifyBackend(params notifyBackendParams) (*notifysubscriptions.Backend, error) {
delivery, err := createDelivery(params.client, params.serverRoot)
delivery, err := createDelivery(params.servicesAPI, params.serverRoot)
if err != nil {
return nil, err
}
@ -72,58 +70,18 @@ func createSubscriptionsNotifyBackend(params notifyBackendParams) (*notifysubscr
return backend, nil
}
func createDelivery(client *pluginapi.Client, serverRoot string) (*plugindelivery.PluginDelivery, error) {
func createDelivery(servicesAPI model.ServicesAPI, serverRoot string) (*plugindelivery.PluginDelivery, error) {
bot := &mm_model.Bot{
Username: botUsername,
DisplayName: botDisplayname,
Description: botDescription,
}
botID, err := client.Bot.EnsureBot(bot)
botID, err := servicesAPI.EnsureBot(bot)
if err != nil {
return nil, fmt.Errorf("failed to ensure %s bot: %w", botDisplayname, err)
}
pluginAPI := &pluginAPIAdapter{client: client}
return plugindelivery.New(botID, serverRoot, pluginAPI), nil
}
// pluginAPIAdapter provides a simple wrapper around the component based Plugin API
// which flattens the API to satisfy an interface.
type pluginAPIAdapter struct {
client *pluginapi.Client
}
func (da *pluginAPIAdapter) GetDirectChannel(userID1, userID2 string) (*mm_model.Channel, error) {
return da.client.Channel.GetDirect(userID1, userID2)
}
func (da *pluginAPIAdapter) CreatePost(post *mm_model.Post) error {
return da.client.Post.CreatePost(post)
}
func (da *pluginAPIAdapter) GetUserByID(userID string) (*mm_model.User, error) {
return da.client.User.Get(userID)
}
func (da *pluginAPIAdapter) GetUserByUsername(name string) (*mm_model.User, error) {
return da.client.User.GetByUsername(name)
}
func (da *pluginAPIAdapter) GetTeamMember(teamID string, userID string) (*mm_model.TeamMember, error) {
return da.client.Team.GetMember(teamID, userID)
}
func (da *pluginAPIAdapter) GetChannelByID(channelID string) (*mm_model.Channel, error) {
return da.client.Channel.Get(channelID)
}
func (da *pluginAPIAdapter) GetChannelMember(channelID string, userID string) (*mm_model.ChannelMember, error) {
return da.client.Channel.GetMember(channelID, userID)
}
func (da *pluginAPIAdapter) CreateMember(teamID string, userID string) (*mm_model.TeamMember, error) {
return da.client.Team.CreateMember(teamID, userID)
return plugindelivery.New(botID, serverRoot, servicesAPI), nil
}
type appIface interface {

View File

@ -0,0 +1,163 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package boards
import (
"encoding/json"
"fmt"
"net/url"
"strings"
mm_model "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/shared/markdown"
)
func postWithBoardsEmbed(post *mm_model.Post) *mm_model.Post {
if _, ok := post.GetProps()["boards"]; ok {
post.AddProp("boards", nil)
}
firstLink, newPostMessage := getFirstLinkAndShortenAllBoardsLink(post.Message)
post.Message = newPostMessage
if firstLink == "" {
return post
}
u, err := url.Parse(firstLink)
if err != nil {
return post
}
// Trim away the first / because otherwise after we split the string, the first element in the array is a empty element
urlPath := u.Path
urlPath = strings.TrimPrefix(urlPath, "/")
urlPath = strings.TrimSuffix(urlPath, "/")
pathSplit := strings.Split(strings.ToLower(urlPath), "/")
queryParams := u.Query()
if len(pathSplit) == 0 {
return post
}
teamID, boardID, viewID, cardID := returnBoardsParams(pathSplit)
if teamID != "" && boardID != "" && viewID != "" && cardID != "" {
b, _ := json.Marshal(BoardsEmbed{
TeamID: teamID,
BoardID: boardID,
ViewID: viewID,
CardID: cardID,
ReadToken: queryParams.Get("r"),
OriginalPath: u.RequestURI(),
})
BoardsPostEmbed := &mm_model.PostEmbed{
Type: mm_model.PostEmbedBoards,
Data: string(b),
}
if post.Metadata == nil {
post.Metadata = &mm_model.PostMetadata{}
}
post.Metadata.Embeds = []*mm_model.PostEmbed{BoardsPostEmbed}
post.AddProp("boards", string(b))
}
return post
}
func getFirstLinkAndShortenAllBoardsLink(postMessage string) (firstLink, newPostMessage string) {
newPostMessage = postMessage
seenLinks := make(map[string]bool)
markdown.Inspect(postMessage, func(blockOrInline interface{}) bool {
if autoLink, ok := blockOrInline.(*markdown.Autolink); ok {
link := autoLink.Destination()
if firstLink == "" {
firstLink = link
}
if seen := seenLinks[link]; !seen && isBoardsLink(link) {
// TODO: Make sure that <Jump To Card> is Internationalized and translated to the Users Language preference
markdownFormattedLink := fmt.Sprintf("[%s](%s)", "<Jump To Card>", link)
newPostMessage = strings.ReplaceAll(newPostMessage, link, markdownFormattedLink)
seenLinks[link] = true
}
}
if inlineLink, ok := blockOrInline.(*markdown.InlineLink); ok {
if link := inlineLink.Destination(); firstLink == "" {
firstLink = link
}
}
return true
})
return firstLink, newPostMessage
}
func returnBoardsParams(pathArray []string) (teamID, boardID, viewID, cardID string) {
// The reason we are doing this search for the first instance of boards or plugins is to take into account URL subpaths
index := -1
for i := 0; i < len(pathArray); i++ {
if pathArray[i] == "boards" || pathArray[i] == "plugins" {
index = i
break
}
}
if index == -1 {
return teamID, boardID, viewID, cardID
}
// If at index, the parameter in the path is boards,
// then we've copied this directly as logged in user of that board
// If at index, the parameter in the path is plugins,
// then we've copied this from a shared board
// For card links copied on a non-shared board, the path looks like {...Mattermost Url}.../boards/team/teamID/boardID/viewID/cardID
// For card links copied on a shared board, the path looks like
// {...Mattermost Url}.../plugins/focalboard/team/teamID/shared/boardID/viewID/cardID?r=read_token
// This is a non-shared board card link
if len(pathArray)-index == 6 && pathArray[index] == "boards" && pathArray[index+1] == "team" {
teamID = pathArray[index+2]
boardID = pathArray[index+3]
viewID = pathArray[index+4]
cardID = pathArray[index+5]
} else if len(pathArray)-index == 8 && pathArray[index] == "plugins" &&
pathArray[index+1] == "focalboard" &&
pathArray[index+2] == "team" &&
pathArray[index+4] == "shared" { // This is a shared board card link
teamID = pathArray[index+3]
boardID = pathArray[index+5]
viewID = pathArray[index+6]
cardID = pathArray[index+7]
}
return teamID, boardID, viewID, cardID
}
func isBoardsLink(link string) bool {
u, err := url.Parse(link)
if err != nil {
return false
}
urlPath := u.Path
urlPath = strings.TrimPrefix(urlPath, "/")
urlPath = strings.TrimSuffix(urlPath, "/")
pathSplit := strings.Split(strings.ToLower(urlPath), "/")
if len(pathSplit) == 0 {
return false
}
teamID, boardID, viewID, cardID := returnBoardsParams(pathSplit)
return teamID != "" && boardID != "" && viewID != "" && cardID != ""
}

View File

@ -1,76 +1,38 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package main
import (
"encoding/json"
"errors"
"fmt"
"math"
"net/http"
"net/url"
"path"
"strings"
"sync"
"github.com/mattermost/focalboard/server/auth"
"github.com/mattermost/focalboard/server/server"
"github.com/mattermost/focalboard/server/services/config"
"github.com/mattermost/focalboard/server/services/notify"
"github.com/mattermost/focalboard/server/services/permissions/mmpermissions"
"github.com/mattermost/focalboard/server/services/store"
"github.com/mattermost/focalboard/server/services/store/mattermostauthlayer"
"github.com/mattermost/focalboard/server/services/store/sqlstore"
"github.com/mattermost/focalboard/server/utils"
"github.com/mattermost/focalboard/server/ws"
"github.com/mattermost/focalboard/mattermost-plugin/server/boards"
pluginapi "github.com/mattermost/mattermost-plugin-api"
"github.com/mattermost/mattermost-plugin-api/cluster"
mmModel "github.com/mattermost/mattermost-server/v6/model"
mm_model "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/plugin"
"github.com/mattermost/mattermost-server/v6/shared/markdown"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
)
const (
boardsFeatureFlagName = "BoardsFeatureFlags"
pluginName = "focalboard"
sharedBoardsName = "enablepublicsharedboards"
notifyFreqCardSecondsKey = "notify_freq_card_seconds"
notifyFreqBoardSecondsKey = "notify_freq_board_seconds"
)
type BoardsEmbed struct {
OriginalPath string `json:"originalPath"`
TeamID string `json:"teamID"`
ViewID string `json:"viewID"`
BoardID string `json:"boardID"`
CardID string `json:"cardID"`
ReadToken string `json:"readToken,omitempty"`
}
var ErrPluginNotAllowed = errors.New("boards plugin not allowed while Boards product enabled")
// Plugin implements the interface expected by the Mattermost server to communicate between the server and plugin processes.
type Plugin struct {
plugin.MattermostPlugin
// configurationLock synchronizes access to the configuration.
configurationLock sync.RWMutex
// configuration is the active plugin configuration. Consult getConfiguration and
// setConfiguration for usage.
configuration *configuration
server *server.Server
wsPluginAdapter ws.PluginAdapterInterface
boardsApp *boards.BoardsApp
}
func (p *Plugin) OnActivate() error {
mmconfig := p.API.GetUnsanitizedConfig()
if p.API.GetConfig().FeatureFlags.BoardsProduct {
p.API.LogError(ErrPluginNotAllowed.Error())
return ErrPluginNotAllowed
}
client := pluginapi.NewClient(p.API, p.Driver)
sqlDB, err := client.Store.GetMasterDB()
if err != nil {
return fmt.Errorf("error initializing the DB: %w", err)
}
logger, _ := mlog.NewLogger()
pluginTargetFactory := newPluginTargetFactory(&client.Log)
@ -78,257 +40,71 @@ func (p *Plugin) OnActivate() error {
TargetFactory: pluginTargetFactory.createTarget,
}
cfgJSON := defaultLoggingConfig()
err = logger.Configure("", cfgJSON, factories)
err := logger.Configure("", cfgJSON, factories)
if err != nil {
return err
}
baseURL := ""
if mmconfig.ServiceSettings.SiteURL != nil {
baseURL = *mmconfig.ServiceSettings.SiteURL
}
serverID := client.System.GetDiagnosticID()
cfg := p.createBoardsConfig(*mmconfig, baseURL, serverID)
adapter := newServiceAPIAdapter(p.API, client.Store, logger)
storeParams := sqlstore.Params{
DBType: cfg.DBType,
ConnectionString: cfg.DBConfigString,
TablePrefix: cfg.DBTablePrefix,
Logger: logger,
DB: sqlDB,
IsPlugin: true,
NewMutexFn: func(name string) (*cluster.Mutex, error) {
return cluster.NewMutex(p.API, name)
},
PluginAPI: &p.API,
}
var db store.Store
db, err = sqlstore.New(storeParams)
boardsApp, err := boards.NewBoardsApp(adapter)
if err != nil {
return fmt.Errorf("error initializing the DB: %w", err)
}
if cfg.AuthMode == server.MattermostAuthMod {
layeredStore, err2 := mattermostauthlayer.New(cfg.DBType, sqlDB, db, logger, p.API, storeParams.TablePrefix, client)
if err2 != nil {
return fmt.Errorf("error initializing the DB: %w", err2)
}
db = layeredStore
return fmt.Errorf("cannot activate plugin: %w", err)
}
permissionsService := mmpermissions.New(db, p.API)
p.wsPluginAdapter = ws.NewPluginAdapter(p.API, auth.New(cfg, db, permissionsService), db, logger)
backendParams := notifyBackendParams{
cfg: cfg,
client: client,
appAPI: &appAPI{store: db},
permissions: permissionsService,
serverRoot: baseURL + "/boards",
logger: logger,
}
var notifyBackends []notify.Backend
mentionsBackend, err := createMentionsNotifyBackend(backendParams)
if err != nil {
return fmt.Errorf("error creating mention notifications backend: %w", err)
}
notifyBackends = append(notifyBackends, mentionsBackend)
subscriptionsBackend, err2 := createSubscriptionsNotifyBackend(backendParams)
if err2 != nil {
return fmt.Errorf("error creating subscription notifications backend: %w", err2)
}
notifyBackends = append(notifyBackends, subscriptionsBackend)
mentionsBackend.AddListener(subscriptionsBackend)
params := server.Params{
Cfg: cfg,
SingleUserToken: "",
DBStore: db,
Logger: logger,
ServerID: serverID,
WSAdapter: p.wsPluginAdapter,
NotifyBackends: notifyBackends,
PermissionsService: permissionsService,
PluginAPI: p.API,
Client: client,
IsPlugin: true,
}
server, err := server.New(params)
if err != nil {
fmt.Println("ERROR INITIALIZING THE SERVER", err)
return err
}
backendParams.appAPI.init(db, server.App())
if utils.IsCloudLicense(p.API.GetLicense()) {
limits, err := p.API.GetCloudLimits()
if err != nil {
fmt.Println("ERROR FETCHING CLOUD LIMITS WHEN STARTING THE PLUGIN", err)
return err
}
if err := server.App().SetCloudLimits(limits); err != nil {
fmt.Println("ERROR SETTING CLOUD LIMITS WHEN STARTING THE PLUGIN", err)
return err
}
}
p.server = server
return server.Start()
p.boardsApp = boardsApp
return p.boardsApp.Start()
}
func (p *Plugin) createBoardsConfig(mmconfig mmModel.Config, baseURL string, serverID string) *config.Configuration {
filesS3Config := config.AmazonS3Config{}
if mmconfig.FileSettings.AmazonS3AccessKeyId != nil {
filesS3Config.AccessKeyID = *mmconfig.FileSettings.AmazonS3AccessKeyId
}
if mmconfig.FileSettings.AmazonS3SecretAccessKey != nil {
filesS3Config.SecretAccessKey = *mmconfig.FileSettings.AmazonS3SecretAccessKey
}
if mmconfig.FileSettings.AmazonS3Bucket != nil {
filesS3Config.Bucket = *mmconfig.FileSettings.AmazonS3Bucket
}
if mmconfig.FileSettings.AmazonS3PathPrefix != nil {
filesS3Config.PathPrefix = *mmconfig.FileSettings.AmazonS3PathPrefix
}
if mmconfig.FileSettings.AmazonS3Region != nil {
filesS3Config.Region = *mmconfig.FileSettings.AmazonS3Region
}
if mmconfig.FileSettings.AmazonS3Endpoint != nil {
filesS3Config.Endpoint = *mmconfig.FileSettings.AmazonS3Endpoint
}
if mmconfig.FileSettings.AmazonS3SSL != nil {
filesS3Config.SSL = *mmconfig.FileSettings.AmazonS3SSL
}
if mmconfig.FileSettings.AmazonS3SignV2 != nil {
filesS3Config.SignV2 = *mmconfig.FileSettings.AmazonS3SignV2
}
if mmconfig.FileSettings.AmazonS3SSE != nil {
filesS3Config.SSE = *mmconfig.FileSettings.AmazonS3SSE
}
if mmconfig.FileSettings.AmazonS3Trace != nil {
filesS3Config.Trace = *mmconfig.FileSettings.AmazonS3Trace
// OnConfigurationChange is invoked when configuration changes may have been made.
func (p *Plugin) OnConfigurationChange() error {
// Have we been setup by OnActivate?
if p.boardsApp == nil {
return nil
}
enableTelemetry := false
if mmconfig.LogSettings.EnableDiagnostics != nil {
enableTelemetry = *mmconfig.LogSettings.EnableDiagnostics
}
enablePublicSharedBoards := false
if mmconfig.PluginSettings.Plugins[pluginName][sharedBoardsName] == true {
enablePublicSharedBoards = true
}
enableBoardsDeletion := false
if mmconfig.DataRetentionSettings.EnableBoardsDeletion != nil {
enableBoardsDeletion = true
}
featureFlags := parseFeatureFlags(mmconfig.FeatureFlags.ToMap())
return &config.Configuration{
ServerRoot: baseURL + "/plugins/focalboard",
Port: -1,
DBType: *mmconfig.SqlSettings.DriverName,
DBConfigString: *mmconfig.SqlSettings.DataSource,
DBTablePrefix: "focalboard_",
UseSSL: false,
SecureCookie: true,
WebPath: path.Join(*mmconfig.PluginSettings.Directory, "focalboard", "pack"),
FilesDriver: *mmconfig.FileSettings.DriverName,
FilesPath: *mmconfig.FileSettings.Directory,
FilesS3Config: filesS3Config,
MaxFileSize: *mmconfig.FileSettings.MaxFileSize,
Telemetry: enableTelemetry,
TelemetryID: serverID,
WebhookUpdate: []string{},
SessionExpireTime: 2592000,
SessionRefreshTime: 18000,
LocalOnly: false,
EnableLocalMode: false,
LocalModeSocketLocation: "",
AuthMode: "mattermost",
EnablePublicSharedBoards: enablePublicSharedBoards,
FeatureFlags: featureFlags,
NotifyFreqCardSeconds: getPluginSettingInt(mmconfig, notifyFreqCardSecondsKey, 120),
NotifyFreqBoardSeconds: getPluginSettingInt(mmconfig, notifyFreqBoardSecondsKey, 86400),
EnableDataRetention: enableBoardsDeletion,
DataRetentionDays: *mmconfig.DataRetentionSettings.BoardsRetentionDays,
TeammateNameDisplay: *mmconfig.TeamSettings.TeammateNameDisplay,
}
}
func getPluginSetting(mmConfig mmModel.Config, key string) (interface{}, bool) {
plugin, ok := mmConfig.PluginSettings.Plugins[pluginName]
if !ok {
return nil, false
}
val, ok := plugin[key]
if !ok {
return nil, false
}
return val, true
}
func getPluginSettingInt(mmConfig mmModel.Config, key string, def int) int {
val, ok := getPluginSetting(mmConfig, key)
if !ok {
return def
}
valFloat, ok := val.(float64)
if !ok {
return def
}
return int(math.Round(valFloat))
}
func parseFeatureFlags(configFeatureFlags map[string]string) map[string]string {
featureFlags := make(map[string]string)
for key, value := range configFeatureFlags {
// Break out FeatureFlags and pass remaining
if key == boardsFeatureFlagName {
for _, flag := range strings.Split(value, "-") {
featureFlags[flag] = "true"
}
} else {
featureFlags[key] = value
}
}
return featureFlags
return p.boardsApp.OnConfigurationChange()
}
func (p *Plugin) OnWebSocketConnect(webConnID, userID string) {
p.wsPluginAdapter.OnWebSocketConnect(webConnID, userID)
p.boardsApp.OnWebSocketConnect(webConnID, userID)
}
func (p *Plugin) OnWebSocketDisconnect(webConnID, userID string) {
p.wsPluginAdapter.OnWebSocketDisconnect(webConnID, userID)
p.boardsApp.OnWebSocketDisconnect(webConnID, userID)
}
func (p *Plugin) WebSocketMessageHasBeenPosted(webConnID, userID string, req *mmModel.WebSocketRequest) {
p.wsPluginAdapter.WebSocketMessageHasBeenPosted(webConnID, userID, req)
func (p *Plugin) WebSocketMessageHasBeenPosted(webConnID, userID string, req *mm_model.WebSocketRequest) {
p.boardsApp.WebSocketMessageHasBeenPosted(webConnID, userID, req)
}
func (p *Plugin) OnDeactivate() error {
return p.server.Shutdown()
return p.boardsApp.Stop()
}
func (p *Plugin) OnPluginClusterEvent(_ *plugin.Context, ev mmModel.PluginClusterEvent) {
p.wsPluginAdapter.HandleClusterEvent(ev)
func (p *Plugin) OnPluginClusterEvent(ctx *plugin.Context, ev mm_model.PluginClusterEvent) {
p.boardsApp.OnPluginClusterEvent(ctx, ev)
}
func (p *Plugin) MessageWillBePosted(ctx *plugin.Context, post *mm_model.Post) (*mm_model.Post, string) {
return p.boardsApp.MessageWillBePosted(ctx, post)
}
func (p *Plugin) MessageWillBeUpdated(ctx *plugin.Context, newPost, oldPost *mm_model.Post) (*mm_model.Post, string) {
return p.boardsApp.MessageWillBeUpdated(ctx, newPost, oldPost)
}
func (p *Plugin) OnCloudLimitsUpdated(limits *mm_model.ProductLimits) {
p.boardsApp.OnCloudLimitsUpdated(limits)
}
func (p *Plugin) RunDataRetention(nowTime, batchSize int64) (int64, error) {
return p.boardsApp.RunDataRetention(nowTime, batchSize)
}
// ServeHTTP demonstrates a plugin that handles HTTP requests by greeting the world.
func (p *Plugin) ServeHTTP(_ *plugin.Context, w http.ResponseWriter, r *http.Request) {
router := p.server.GetRootRouter()
router.ServeHTTP(w, r)
func (p *Plugin) ServeHTTP(ctx *plugin.Context, w http.ResponseWriter, r *http.Request) {
p.boardsApp.ServeHTTP(ctx, w, r)
}
func defaultLoggingConfig() string {
@ -371,166 +147,3 @@ func defaultLoggingConfig() string {
}
}`
}
func (p *Plugin) MessageWillBePosted(_ *plugin.Context, post *mmModel.Post) (*mmModel.Post, string) {
return postWithBoardsEmbed(post), ""
}
func (p *Plugin) MessageWillBeUpdated(_ *plugin.Context, newPost, _ *mmModel.Post) (*mmModel.Post, string) {
return postWithBoardsEmbed(newPost), ""
}
func postWithBoardsEmbed(post *mmModel.Post) *mmModel.Post {
if _, ok := post.GetProps()["boards"]; ok {
post.AddProp("boards", nil)
}
firstLink, newPostMessage := getFirstLinkAndShortenAllBoardsLink(post.Message)
post.Message = newPostMessage
if firstLink == "" {
return post
}
u, err := url.Parse(firstLink)
if err != nil {
return post
}
// Trim away the first / because otherwise after we split the string, the first element in the array is a empty element
urlPath := u.Path
urlPath = strings.TrimPrefix(urlPath, "/")
urlPath = strings.TrimSuffix(urlPath, "/")
pathSplit := strings.Split(strings.ToLower(urlPath), "/")
queryParams := u.Query()
if len(pathSplit) == 0 {
return post
}
teamID, boardID, viewID, cardID := returnBoardsParams(pathSplit)
if teamID != "" && boardID != "" && viewID != "" && cardID != "" {
b, _ := json.Marshal(BoardsEmbed{
TeamID: teamID,
BoardID: boardID,
ViewID: viewID,
CardID: cardID,
ReadToken: queryParams.Get("r"),
OriginalPath: u.RequestURI(),
})
BoardsPostEmbed := &mmModel.PostEmbed{
Type: mmModel.PostEmbedBoards,
Data: string(b),
}
if post.Metadata == nil {
post.Metadata = &mmModel.PostMetadata{}
}
post.Metadata.Embeds = []*mmModel.PostEmbed{BoardsPostEmbed}
post.AddProp("boards", string(b))
}
return post
}
func getFirstLinkAndShortenAllBoardsLink(postMessage string) (firstLink, newPostMessage string) {
newPostMessage = postMessage
seenLinks := make(map[string]bool)
markdown.Inspect(postMessage, func(blockOrInline interface{}) bool {
if autoLink, ok := blockOrInline.(*markdown.Autolink); ok {
link := autoLink.Destination()
if firstLink == "" {
firstLink = link
}
if seen := seenLinks[link]; !seen && isBoardsLink(link) {
// TODO: Make sure that <Jump To Card> is Internationalized and translated to the Users Language preference
markdownFormattedLink := fmt.Sprintf("[%s](%s)", "<Jump To Card>", link)
newPostMessage = strings.ReplaceAll(newPostMessage, link, markdownFormattedLink)
seenLinks[link] = true
}
}
if inlineLink, ok := blockOrInline.(*markdown.InlineLink); ok {
if link := inlineLink.Destination(); firstLink == "" {
firstLink = link
}
}
return true
})
return firstLink, newPostMessage
}
func returnBoardsParams(pathArray []string) (teamID, boardID, viewID, cardID string) {
// The reason we are doing this search for the first instance of boards or plugins is to take into account URL subpaths
index := -1
for i := 0; i < len(pathArray); i++ {
if pathArray[i] == "boards" || pathArray[i] == "plugins" {
index = i
break
}
}
if index == -1 {
return teamID, boardID, viewID, cardID
}
// If at index, the parameter in the path is boards,
// then we've copied this directly as logged in user of that board
// If at index, the parameter in the path is plugins,
// then we've copied this from a shared board
// For card links copied on a non-shared board, the path looks like {...Mattermost Url}.../boards/team/teamID/boardID/viewID/cardID
// For card links copied on a shared board, the path looks like
// {...Mattermost Url}.../plugins/focalboard/team/teamID/shared/boardID/viewID/cardID?r=read_token
// This is a non-shared board card link
if len(pathArray)-index == 6 && pathArray[index] == "boards" && pathArray[index+1] == "team" {
teamID = pathArray[index+2]
boardID = pathArray[index+3]
viewID = pathArray[index+4]
cardID = pathArray[index+5]
} else if len(pathArray)-index == 8 && pathArray[index] == "plugins" &&
pathArray[index+1] == "focalboard" &&
pathArray[index+2] == "team" &&
pathArray[index+4] == "shared" { // This is a shared board card link
teamID = pathArray[index+3]
boardID = pathArray[index+5]
viewID = pathArray[index+6]
cardID = pathArray[index+7]
}
return teamID, boardID, viewID, cardID
}
func isBoardsLink(link string) bool {
u, err := url.Parse(link)
if err != nil {
return false
}
urlPath := u.Path
urlPath = strings.TrimPrefix(urlPath, "/")
urlPath = strings.TrimSuffix(urlPath, "/")
pathSplit := strings.Split(strings.ToLower(urlPath), "/")
if len(pathSplit) == 0 {
return false
}
teamID, boardID, viewID, cardID := returnBoardsParams(pathSplit)
return teamID != "" && boardID != "" && viewID != "" && cardID != ""
}
func (p *Plugin) OnCloudLimitsUpdated(limits *mmModel.ProductLimits) {
if err := p.server.App().SetCloudLimits(limits); err != nil {
fmt.Println("Error setting the cloud limits for Boards", err)
}
}

View File

@ -53,7 +53,7 @@ type API struct {
permissions permissions.PermissionsService
singleUserToken string
MattermostAuth bool
logger *mlog.Logger
logger mlog.LoggerIFace
audit *audit.Audit
isPlugin bool
}
@ -63,7 +63,7 @@ func NewAPI(
singleUserToken string,
authService string,
permissions permissions.PermissionsService,
logger *mlog.Logger,
logger mlog.LoggerIFace,
audit *audit.Audit,
isPlugin bool,
) *API {

View File

@ -1,6 +1,7 @@
package app
import (
"io"
"sync"
"time"
@ -14,8 +15,7 @@ import (
"github.com/mattermost/focalboard/server/utils"
"github.com/mattermost/focalboard/server/ws"
mmModel "github.com/mattermost/mattermost-server/v6/model"
mm_model "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/shared/filestore"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
)
@ -26,21 +26,32 @@ const (
blockChangeNotifierShutdownTimeout = time.Second * 10
)
type pluginAPI interface {
GetUsers(options *mmModel.UserGetOptions) ([]*mmModel.User, *mmModel.AppError)
type servicesAPI interface {
GetUsersFromProfiles(options *mm_model.UserGetOptions) ([]*mm_model.User, error)
}
type ReadCloseSeeker = filestore.ReadCloseSeeker
type fileBackend interface {
Reader(path string) (ReadCloseSeeker, error)
FileExists(path string) (bool, error)
CopyFile(oldPath, newPath string) error
MoveFile(oldPath, newPath string) error
WriteFile(fr io.Reader, path string) (int64, error)
RemoveFile(path string) error
}
type Services struct {
Auth *auth.Auth
Store store.Store
FilesBackend filestore.FileBackend
FilesBackend fileBackend
Webhook *webhook.Client
Metrics *metrics.Metrics
Notifications *notify.Service
Logger *mlog.Logger
Logger mlog.LoggerIFace
Permissions permissions.PermissionsService
SkipTemplateInit bool
PluginAPI pluginAPI
ServicesAPI servicesAPI
}
type App struct {
@ -48,13 +59,13 @@ type App struct {
store store.Store
auth *auth.Auth
wsAdapter ws.Adapter
filesBackend filestore.FileBackend
filesBackend fileBackend
webhook *webhook.Client
metrics *metrics.Metrics
notifications *notify.Service
logger *mlog.Logger
logger mlog.LoggerIFace
blockChangeNotifier *utils.CallbackQueue
pluginAPI pluginAPI
servicesAPI servicesAPI
cardLimitMux sync.RWMutex
cardLimit int
@ -80,7 +91,7 @@ func New(config *config.Configuration, wsAdapter ws.Adapter, services Services)
notifications: services.Notifications,
logger: services.Logger,
blockChangeNotifier: utils.NewCallbackQueue("blockChangeNotifier", blockChangeNotifierQueueSize, blockChangeNotifierPoolSize, services.Logger),
pluginAPI: services.PluginAPI,
servicesAPI: services.ServicesAPI,
}
app.initialize(services.SkipTemplateInit)
return app

View File

@ -267,7 +267,7 @@ func (eb *errBoardNotFoundInTemplateMap) Error() string {
}
func (a *App) NotifyPortalAdminsUpgradeRequest(teamID string) error {
if a.pluginAPI == nil {
if a.servicesAPI == nil {
return ErrNilPluginAPI
}
@ -295,7 +295,7 @@ func (a *App) NotifyPortalAdminsUpgradeRequest(teamID string) error {
for ; true; page++ {
getUsersOptions.Page = page
systemAdmins, appErr := a.pluginAPI.GetUsers(getUsersOptions)
systemAdmins, appErr := a.servicesAPI.GetUsersFromProfiles(getUsersOptions)
if appErr != nil {
a.logger.Error("failed to fetch system admins", mlog.Int("page_size", getUsersOptions.PerPage), mlog.Int("page", page), mlog.Err(appErr))
return appErr

View File

@ -7,7 +7,6 @@ import (
"database/sql"
"testing"
"github.com/mattermost/mattermost-server/v6/plugin/plugintest"
"github.com/stretchr/testify/assert"
"github.com/golang/mock/gomock"
@ -16,6 +15,7 @@ import (
mmModel "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/focalboard/server/model"
mockservicesapi "github.com/mattermost/focalboard/server/model/mocks"
)
func TestIsCloud(t *testing.T) {
@ -649,7 +649,8 @@ func TestNotifyPortalAdminsUpgradeRequest(t *testing.T) {
defer tearDown()
t.Run("should send message", func(t *testing.T) {
pluginAPI := &plugintest.API{}
ctrl := gomock.NewController(t)
servicesAPI := mockservicesapi.NewMockServicesAPI(ctrl)
sysAdmin1 := &mmModel.User{
Id: "michael-scott",
@ -667,7 +668,7 @@ func TestNotifyPortalAdminsUpgradeRequest(t *testing.T) {
PerPage: 50,
Page: 0,
}
pluginAPI.On("GetUsers", getUsersOptionsPage0).Return([]*mmModel.User{sysAdmin1, sysAdmin2}, nil).Once()
servicesAPI.EXPECT().GetUsersFromProfiles(getUsersOptionsPage0).Return([]*mmModel.User{sysAdmin1, sysAdmin2}, nil)
getUsersOptionsPage1 := &mmModel.UserGetOptions{
Active: true,
@ -675,9 +676,9 @@ func TestNotifyPortalAdminsUpgradeRequest(t *testing.T) {
PerPage: 50,
Page: 1,
}
pluginAPI.On("GetUsers", getUsersOptionsPage1).Return([]*mmModel.User{}, nil).Once()
servicesAPI.EXPECT().GetUsersFromProfiles(getUsersOptionsPage1).Return([]*mmModel.User{}, nil)
th.App.pluginAPI = pluginAPI
th.App.servicesAPI = servicesAPI
team := &model.Team{
Title: "Dunder Mifflin",
@ -691,7 +692,8 @@ func TestNotifyPortalAdminsUpgradeRequest(t *testing.T) {
})
t.Run("no sys admins found", func(t *testing.T) {
pluginAPI := &plugintest.API{}
ctrl := gomock.NewController(t)
servicesAPI := mockservicesapi.NewMockServicesAPI(ctrl)
getUsersOptionsPage0 := &mmModel.UserGetOptions{
Active: true,
@ -699,9 +701,9 @@ func TestNotifyPortalAdminsUpgradeRequest(t *testing.T) {
PerPage: 50,
Page: 0,
}
pluginAPI.On("GetUsers", getUsersOptionsPage0).Return([]*mmModel.User{}, nil).Once()
servicesAPI.EXPECT().GetUsersFromProfiles(getUsersOptionsPage0).Return([]*mmModel.User{}, nil)
th.App.pluginAPI = pluginAPI
th.App.servicesAPI = servicesAPI
team := &model.Team{
Title: "Dunder Mifflin",
@ -714,7 +716,8 @@ func TestNotifyPortalAdminsUpgradeRequest(t *testing.T) {
})
t.Run("iterate multiple pages", func(t *testing.T) {
pluginAPI := &plugintest.API{}
ctrl := gomock.NewController(t)
servicesAPI := mockservicesapi.NewMockServicesAPI(ctrl)
sysAdmin1 := &mmModel.User{
Id: "michael-scott",
@ -732,7 +735,7 @@ func TestNotifyPortalAdminsUpgradeRequest(t *testing.T) {
PerPage: 50,
Page: 0,
}
pluginAPI.On("GetUsers", getUsersOptionsPage0).Return([]*mmModel.User{sysAdmin1}, nil).Once()
servicesAPI.EXPECT().GetUsersFromProfiles(getUsersOptionsPage0).Return([]*mmModel.User{sysAdmin1}, nil)
getUsersOptionsPage1 := &mmModel.UserGetOptions{
Active: true,
@ -740,7 +743,7 @@ func TestNotifyPortalAdminsUpgradeRequest(t *testing.T) {
PerPage: 50,
Page: 1,
}
pluginAPI.On("GetUsers", getUsersOptionsPage1).Return([]*mmModel.User{sysAdmin2}, nil).Once()
servicesAPI.EXPECT().GetUsersFromProfiles(getUsersOptionsPage1).Return([]*mmModel.User{sysAdmin2}, nil)
getUsersOptionsPage2 := &mmModel.UserGetOptions{
Active: true,
@ -748,9 +751,9 @@ func TestNotifyPortalAdminsUpgradeRequest(t *testing.T) {
PerPage: 50,
Page: 2,
}
pluginAPI.On("GetUsers", getUsersOptionsPage2).Return([]*mmModel.User{}, nil).Once()
servicesAPI.EXPECT().GetUsersFromProfiles(getUsersOptionsPage2).Return([]*mmModel.User{}, nil)
th.App.pluginAPI = pluginAPI
th.App.servicesAPI = servicesAPI
team := &model.Team{
Title: "Dunder Mifflin",

View File

@ -22,7 +22,7 @@ type TestHelper struct {
App *App
Store *mockstore.MockStore
FilesBackend *mocks.FileBackend
logger *mlog.Logger
logger mlog.LoggerIFace
}
func SetupTestHelper(t *testing.T) (*TestHelper, func()) {

View File

@ -2,8 +2,6 @@ module github.com/mattermost/focalboard/server
go 1.18
replace github.com/mattermost/mattermost-server/v6 => github.com/mattermost/mattermost-server/v6 v6.0.0-20220613202234-182ae1234a49
require (
github.com/Masterminds/squirrel v1.5.2
github.com/go-sql-driver/mysql v1.6.0
@ -11,9 +9,9 @@ require (
github.com/gorilla/mux v1.8.0
github.com/gorilla/websocket v1.5.0
github.com/krolaw/zipstream v0.0.0-20180621105154-0a2661891f94
github.com/lib/pq v1.10.5
github.com/mattermost/mattermost-plugin-api v0.0.27
github.com/mattermost/mattermost-server/v6 v6.3.0
github.com/lib/pq v1.10.6
github.com/mattermost/mattermost-plugin-api v0.0.28-0.20220623051512-0afd85e854d4
github.com/mattermost/mattermost-server/v6 v6.0.0-20220711175838-7ee7523729e6
github.com/mattermost/morph v0.0.0-20220401091636-39f834798da8
github.com/mattn/go-sqlite3 v2.0.3+incompatible
github.com/oklog/run v1.1.0
@ -22,15 +20,14 @@ require (
github.com/rudderlabs/analytics-go v3.3.2+incompatible
github.com/sergi/go-diff v1.2.0
github.com/spf13/viper v1.10.1
github.com/stretchr/testify v1.7.1
github.com/stretchr/testify v1.7.2
github.com/wiggin77/merror v1.0.3
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e
)
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver v3.5.1+incompatible // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
@ -42,14 +39,14 @@ require (
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/graph-gophers/graphql-go v1.4.0 // indirect
github.com/hashicorp/go-hclog v1.2.0 // indirect
github.com/hashicorp/go-hclog v1.2.1 // indirect
github.com/hashicorp/go-plugin v1.4.4 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/klauspost/compress v1.15.3 // indirect
github.com/klauspost/cpuid/v2 v2.0.12 // indirect
github.com/klauspost/compress v1.15.6 // indirect
github.com/klauspost/cpuid/v2 v2.0.13 // indirect
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
github.com/magiconair/properties v1.8.6 // indirect
@ -60,7 +57,7 @@ require (
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/minio-go/v7 v7.0.26 // indirect
github.com/minio/minio-go/v7 v7.0.28 // indirect
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
@ -72,7 +69,7 @@ require (
github.com/philhofer/fwd v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/common v0.33.0 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/rs/xid v1.4.0 // indirect
@ -93,19 +90,18 @@ require (
github.com/wiggin77/srslog v1.0.1 // indirect
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect
github.com/yuin/goldmark v1.4.12 // indirect
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/net v0.0.0-20220614195744-fb05da6f9022 // indirect
golang.org/x/sys v0.0.0-20220614162138-6c1b26c55098 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/tools v0.1.10 // indirect
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3 // indirect
google.golang.org/grpc v1.46.0 // indirect
golang.org/x/tools v0.1.11 // indirect
google.golang.org/genproto v0.0.0-20220614165028-45ed7f3ff16e // indirect
google.golang.org/grpc v1.47.0 // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/ini.v1 v1.66.4 // indirect
gopkg.in/ini.v1 v1.66.6 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/uint128 v1.2.0 // indirect
modernc.org/cc/v3 v3.35.24 // indirect
modernc.org/ccgo/v3 v3.15.17 // indirect

View File

@ -130,6 +130,7 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/RoaringBitmap/roaring v0.9.4/go.mod h1:icnadbWcNyfEHlYdr+tDlOTih1Bf/h+rzPpv4sbomAA=
github.com/RoaringBitmap/roaring v1.2.1/go.mod h1:icnadbWcNyfEHlYdr+tDlOTih1Bf/h+rzPpv4sbomAA=
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
github.com/advancedlogic/GoOse v0.0.0-20191112112754-e742535969c1/go.mod h1:f3HCSN1fBWjcpGtXyM119MJgeQl838v6so/PQOqvE1w=
@ -164,7 +165,7 @@ github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:l
github.com/avct/uasurfer v0.0.0-20191028135549-26b5daa857f1/go.mod h1:noBAuukeYOXa0aXGqxr24tADqkwDO2KRD15FsuaZ5a8=
github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.44.9/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go v1.44.34/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go-v2 v1.8.0/go.mod h1:xEFuWz+3TYdlPRuo+CqATbeDWIWyaT5uAPwPaWtgse0=
github.com/aws/aws-sdk-go-v2 v1.9.2/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
github.com/aws/aws-sdk-go-v2/config v1.6.0/go.mod h1:TNtBVmka80lRPk5+S9ZqVfFszOQAGJJ9KbT3EM3CHNU=
@ -210,27 +211,34 @@ github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqO
github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/blevesearch/bleve/v2 v2.3.2/go.mod h1:96+xE5pZUOsr3Y4vHzV1cBC837xZCpwLlX0hrrxnvIg=
github.com/blevesearch/bleve_index_api v1.0.1/go.mod h1:fiwKS0xLEm+gBRgv5mumf0dhgFr2mDgZah1pqv1c1M4=
github.com/blevesearch/bleve_index_api v1.0.2/go.mod h1:fiwKS0xLEm+gBRgv5mumf0dhgFr2mDgZah1pqv1c1M4=
github.com/blevesearch/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:9eJDeqxJ3E7WnLebQUlPD7ZjSce7AnDb9vjGmMCbD0A=
github.com/blevesearch/go-porterstemmer v1.0.3/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M=
github.com/blevesearch/goleveldb v1.0.1/go.mod h1:WrU8ltZbIp0wAoig/MHbrPCXSOLpe79nz5lv5nqfYrQ=
github.com/blevesearch/gtreap v0.1.1/go.mod h1:QaQyDRAT51sotthUWAH4Sj08awFSSWzgYICSZ3w0tYk=
github.com/blevesearch/mmap-go v1.0.2/go.mod h1:ol2qBqYaOUsGdm7aRMRrYGgPvnwLe6Y+7LMvAB5IbSA=
github.com/blevesearch/mmap-go v1.0.3/go.mod h1:pYvKl/grLQrBxuaRYgoTssa4rVujYYeenDp++2E+yvs=
github.com/blevesearch/mmap-go v1.0.4/go.mod h1:EWmEAOmdAS9z/pi/+Toxu99DnsbhG1TIxUoRmJw/pSs=
github.com/blevesearch/scorch_segment_api/v2 v2.1.0/go.mod h1:uch7xyyO/Alxkuxa+CGs79vw0QY8BENSBjg6Mw5L5DE=
github.com/blevesearch/segment v0.9.0/go.mod h1:9PfHYUdQCgHktBgvtUOF4x+pc4/l8rdH0u5spnW85UQ=
github.com/blevesearch/snowball v0.6.1/go.mod h1:ZF0IBg5vgpeoUhnMza2v0A/z8m1cWPlwhke08LpNusg=
github.com/blevesearch/snowballstem v0.9.0/go.mod h1:PivSj3JMc8WuaFkTSRDW2SlrulNWPl4ABg1tC/hlgLs=
github.com/blevesearch/upsidedown_store_api v1.0.1/go.mod h1:MQDVGpHZrpe3Uy26zJBf/a8h0FZY6xJbthIMm8myH2Q=
github.com/blevesearch/vellum v1.0.7/go.mod h1:doBZpmRhwTsASB4QdUZANlJvqVAUdUyX0ZK7QJCTeBE=
github.com/blevesearch/vellum v1.0.8/go.mod h1:+cpRi/tqq49xUYSQN2P7A5zNSNrS+MscLeeaZ3J46UA=
github.com/blevesearch/zapx/v11 v11.3.3/go.mod h1:YzTfUm4kS3e8OmTXDHVV8OzC5MWPO/VPJZQgPNVb4Lc=
github.com/blevesearch/zapx/v11 v11.3.4/go.mod h1:HJ7qdfBxdziuymKvXbsBVhCK5pB98tdzQbc8pJV6tJo=
github.com/blevesearch/zapx/v12 v12.3.3/go.mod h1:RMl6lOZqF+sTxKvhQDJ5yK2LT3Mu7E2p/jGdjAaiRxs=
github.com/blevesearch/zapx/v12 v12.3.4/go.mod h1:uQrKrK9XjXAAsJfAIE8ViLqIKP/keA2DQhS1XXpjkwA=
github.com/blevesearch/zapx/v13 v13.3.3/go.mod h1:eppobNM35U4C22yDvTuxV9xPqo10pwfP/jugL4INWG4=
github.com/blevesearch/zapx/v13 v13.3.4/go.mod h1:Wl7hO1gT+IDvJb7i06g2iW5Qvw0KzncJPsBx7WGWhLA=
github.com/blevesearch/zapx/v14 v14.3.3/go.mod h1:zXNcVzukh0AvG57oUtT1T0ndi09H0kELNaNmekEy0jw=
github.com/blevesearch/zapx/v14 v14.3.4/go.mod h1:b1YhRXXhAj9i+9aOwhRKCHUmJyYieK/QbDvPJDLddUk=
github.com/blevesearch/zapx/v15 v15.3.3/go.mod h1:C+f/97ZzTzK6vt/7sVlZdzZxKu+5+j4SrGCvr9dJzaY=
github.com/blevesearch/zapx/v15 v15.3.4/go.mod h1:TQ/qDC2q7TSSpeC6Vgr9fDN56Ra0u49lZJQ4v30WEx4=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
@ -526,10 +534,12 @@ github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3I
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
@ -767,8 +777,8 @@ github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brv
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM=
github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-hclog v1.2.1 h1:YQsLlGDJgwhXFpucSPyVbCBviQtjlHv3jLTlp8YmtEw=
github.com/hashicorp/go-hclog v1.2.1/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
@ -920,16 +930,16 @@ github.com/klauspost/compress v1.13.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.3 h1:wmfu2iqj9q22SyMINp1uQ8C2/V4M1phJdmH9fG4nba0=
github.com/klauspost/compress v1.15.3/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/klauspost/compress v1.15.6 h1:6D9PcO8QWu0JyaQ2zUMmu16T1T+zjjEpP91guRsvDfY=
github.com/klauspost/compress v1.15.6/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4=
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE=
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/cpuid/v2 v2.0.13 h1:1XxvOiqXZ8SULZUKim/wncr3wZ38H4yCuVDvKdK9OGs=
github.com/klauspost/cpuid/v2 v2.0.13/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@ -966,9 +976,8 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.5 h1:J+gdV2cUmX7ZqL2B0lFcW0m+egaHC2V3lpO8nWxyYiQ=
github.com/lib/pq v1.10.5/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs=
github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w=
@ -994,10 +1003,11 @@ github.com/mattermost/ldap v0.0.0-20201202150706-ee0e6284187d h1:/RJ/UV7M5c7L2TQ
github.com/mattermost/ldap v0.0.0-20201202150706-ee0e6284187d/go.mod h1:HLbgMEI5K131jpxGazJ97AxfPDt31osq36YS1oxFQPQ=
github.com/mattermost/logr/v2 v2.0.15 h1:+WNbGcsc3dBao65eXlceB6dTILNJRIrvubnsTl3zBew=
github.com/mattermost/logr/v2 v2.0.15/go.mod h1:mpPp935r5dIkFDo2y9Q87cQWhFR/4xXpNh0k/y8Hmwg=
github.com/mattermost/mattermost-plugin-api v0.0.27 h1:zFKQ6JW1/f0MfR5dP9P2umNNYVcLtTO74mM/PrVPNC4=
github.com/mattermost/mattermost-plugin-api v0.0.27/go.mod h1:MM+tZ+36Obm9jqcveoxY2RFbwLaZKZUgR1zUlc0UBYw=
github.com/mattermost/mattermost-server/v6 v6.0.0-20220613202234-182ae1234a49 h1:7uFRdTX54qUp7jNodn0+vrhxuwnudHxWRv7kLN72Fig=
github.com/mattermost/mattermost-server/v6 v6.0.0-20220613202234-182ae1234a49/go.mod h1:HBSu5YC0k8TLb+7DFFB9/63/+oBZj7pgx8K07lHmzyI=
github.com/mattermost/mattermost-plugin-api v0.0.28-0.20220623051512-0afd85e854d4 h1:TF1yBBsLntuNb3wc3DRg30S9i6tv1JwtREtXd7Gnv9E=
github.com/mattermost/mattermost-plugin-api v0.0.28-0.20220623051512-0afd85e854d4/go.mod h1:jtiaM6selJi1Od1zGZDGO78hZyG0gI4/I2/8mza4OZg=
github.com/mattermost/mattermost-server/v6 v6.0.0-20220622145221-00016e3a4ff4/go.mod h1:e2CtTtnty6oH8CiHm40cMOqJ+dJeWEK39/tobCkeMAk=
github.com/mattermost/mattermost-server/v6 v6.0.0-20220711175838-7ee7523729e6 h1:lfkO5s/ZwuD2esAHGX+0EtmcsAVXJ0S5Xn37uWW/WoQ=
github.com/mattermost/mattermost-server/v6 v6.0.0-20220711175838-7ee7523729e6/go.mod h1:e2CtTtnty6oH8CiHm40cMOqJ+dJeWEK39/tobCkeMAk=
github.com/mattermost/morph v0.0.0-20220401091636-39f834798da8 h1:gwliVjCTqAC01mSCNqa5nJ/4MmGq50vrjsottIhQ4d8=
github.com/mattermost/morph v0.0.0-20220401091636-39f834798da8/go.mod h1:jxM3g1bx+k2Thz7jofcHguBS8TZn5Pc+o5MGmORObhw=
github.com/mattermost/rsc v0.0.0-20160330161541-bbaefb05eaa0/go.mod h1:nV5bfVpT//+B1RPD2JvRnxbkLmJEYXmRaaVl15fsXjs=
@ -1053,8 +1063,8 @@ github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WT
github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw=
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
github.com/minio/minio-go/v7 v7.0.26 h1:D0HK+8793etZfRY/vHhDmFaP+vmT41K3K4JV9vmZCBQ=
github.com/minio/minio-go/v7 v7.0.26/go.mod h1:x81+AX5gHSfCSqw7jxRKHvxUXMlE5uKX0Vb75Xk5yYg=
github.com/minio/minio-go/v7 v7.0.28 h1:VMr3K5qGIEt+/KW3poopRh8mzi5RwuCjmrmstK196Fg=
github.com/minio/minio-go/v7 v7.0.28/go.mod h1:x81+AX5gHSfCSqw7jxRKHvxUXMlE5uKX0Vb75Xk5yYg=
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
@ -1254,8 +1264,9 @@ github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.33.0 h1:rHgav/0a6+uYgGdNt3jwz8FNSesO/Hsang3O0T9A5SE=
github.com/prometheus/common v0.33.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE=
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
@ -1295,7 +1306,6 @@ github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY=
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/rudderlabs/analytics-go v3.3.1+incompatible/go.mod h1:LF8/ty9kUX4PTY3l5c97K3nZZaX5Hwsvt+NBaRL/f30=
github.com/rudderlabs/analytics-go v3.3.2+incompatible h1:bDajEJTYhfHjNYxbQFMA/2dHlOjyeSgxS7GPIdMZ52Q=
github.com/rudderlabs/analytics-go v3.3.2+incompatible/go.mod h1:LF8/ty9kUX4PTY3l5c97K3nZZaX5Hwsvt+NBaRL/f30=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
@ -1420,8 +1430,9 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
@ -1608,8 +1619,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122 h1:NvGWuYG8dkDHFSKksI1P9faiVJ9rayE6l0+ouWVIDs8=
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM=
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -1635,7 +1646,7 @@ golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+o
golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/image v0.0.0-20220601225756-64ec528b34cd/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@ -1662,8 +1673,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -1742,8 +1753,8 @@ golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20220111093109-d55c255bac03/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220614195744-fb05da6f9022 h1:0qjDla5xICC2suMtyRH/QqX3B1btXTfNsIt/i4LFgO0=
golang.org/x/net v0.0.0-20220614195744-fb05da6f9022/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -1765,6 +1776,7 @@ golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -1778,6 +1790,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180224232135-f6cff0780e54/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -1910,8 +1923,10 @@ golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220317061510-51cd9980dadf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220614162138-6c1b26c55098 h1:PgOr27OhUx2IRqGJ2RxAWI4dJQ7bi9cSrB82uzFzfUA=
golang.org/x/sys v0.0.0-20220614162138-6c1b26c55098/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@ -2021,16 +2036,16 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/tools v0.1.11 h1:loJ25fNOEhSXfHrpoGj91eCUThwdNX6u24rO1xnNteY=
golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0=
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0=
@ -2161,8 +2176,8 @@ google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ6
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220111164026-67b88f271998/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3 h1:q1kiSVscqoDeqTF27eQ2NnLLDmqF0I373qQNXYMy0fo=
google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
google.golang.org/genproto v0.0.0-20220614165028-45ed7f3ff16e h1:ubR4JUtqN3ffdFjpKylv8scWk/mZstGmzXbgYSkuMl0=
google.golang.org/genproto v0.0.0-20220614165028-45ed7f3ff16e/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
@ -2200,8 +2215,8 @@ google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9K
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
google.golang.org/grpc v1.46.0 h1:oCjezcn6g6A75TGoKYBPgKmVBLexhYLM6MebdrPApP8=
google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8=
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@ -2238,8 +2253,8 @@ gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4=
gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI=
gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
@ -2264,8 +2279,9 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/postgres v1.0.8/go.mod h1:4eOzrI1MUfm6ObJU/UcmbXyiHSs8jSwH95G5P5dxcAg=
gorm.io/gorm v1.20.12/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.21.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=

View File

@ -67,7 +67,6 @@ type TestHelper struct {
type FakePermissionPluginAPI struct{}
func (*FakePermissionPluginAPI) LogError(str string, params ...interface{}) {}
func (*FakePermissionPluginAPI) HasPermissionToTeam(userID string, teamID string, permission *mmModel.Permission) bool {
if userID == userNoTeamMember {
return false
@ -195,7 +194,7 @@ func NewTestServerPluginMode() *server.Server {
db := NewPluginTestStore(innerStore)
permissionsService := mmpermissions.New(db, &FakePermissionPluginAPI{})
permissionsService := mmpermissions.New(db, &FakePermissionPluginAPI{}, logger)
params := server.Params{
Cfg: cfg,
@ -345,7 +344,11 @@ func (th *TestHelper) InitBasic() *TestHelper {
var ErrRegisterFail = errors.New("register failed")
func (th *TestHelper) TearDown() {
defer func() { _ = th.Server.Logger().Shutdown() }()
logger := th.Server.Logger()
if l, ok := logger.(*mlog.Logger); ok {
defer func() { _ = l.Shutdown() }()
}
err := th.Server.Shutdown()
if err != nil {
@ -355,7 +358,7 @@ func (th *TestHelper) TearDown() {
os.RemoveAll(th.Server.Config().FilesPath)
if err := os.Remove(th.Server.Config().DBConfigString); err == nil {
th.Server.Logger().Debug("Removed test database", mlog.String("file", th.Server.Config().DBConfigString))
logger.Debug("Removed test database", mlog.String("file", th.Server.Config().DBConfigString))
}
}

View File

@ -263,11 +263,16 @@ func stopServer() {
return
}
logger := pServer.Logger()
err := pServer.Shutdown()
if err != nil {
pServer.Logger().Error("server.Shutdown ERROR", mlog.Err(err))
logger.Error("server.Shutdown ERROR", mlog.Err(err))
}
if l, ok := logger.(*mlog.Logger); ok {
_ = l.Shutdown()
}
_ = pServer.Logger().Shutdown()
pServer = nil
}

View File

@ -12,7 +12,7 @@ import (
// keeping consistent any references that other blocks would made to
// the original IDs, so a tree of blocks can get new IDs and maintain
// its shape.
func GenerateBlockIDs(blocks []Block, logger *mlog.Logger) []Block {
func GenerateBlockIDs(blocks []Block, logger mlog.LoggerIFace) []Block {
blockIDs := map[string]BlockType{}
referenceIDs := map[string]bool{}
for _, block := range blocks {
@ -99,7 +99,7 @@ func GenerateBlockIDs(blocks []Block, logger *mlog.Logger) []Block {
return newBlocks
}
func fixFieldIDs(block *Block, fieldName string, getExistingOrOldID func(string) string, logger *mlog.Logger) {
func fixFieldIDs(block *Block, fieldName string, getExistingOrOldID func(string) string, logger mlog.LoggerIFace) {
field, typeOk := block.Fields[fieldName].([]interface{})
if !typeOk {
logger.Warn(

View File

@ -134,7 +134,7 @@ func (dbab *PatchBoardsAndBlocks) IsValid() error {
return nil
}
func GenerateBoardsAndBlocksIDs(bab *BoardsAndBlocks, logger *mlog.Logger) (*BoardsAndBlocks, error) {
func GenerateBoardsAndBlocksIDs(bab *BoardsAndBlocks, logger mlog.LoggerIFace) (*BoardsAndBlocks, error) {
if err := bab.IsValid(); err != nil {
return nil, err
}

View File

@ -0,0 +1,402 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/mattermost/focalboard/server/model (interfaces: ServicesAPI)
// Package mocks is a generated GoMock package.
package mocks
import (
sql "database/sql"
reflect "reflect"
gomock "github.com/golang/mock/gomock"
model "github.com/mattermost/mattermost-server/v6/model"
mlog "github.com/mattermost/mattermost-server/v6/shared/mlog"
)
// MockServicesAPI is a mock of ServicesAPI interface.
type MockServicesAPI struct {
ctrl *gomock.Controller
recorder *MockServicesAPIMockRecorder
}
// MockServicesAPIMockRecorder is the mock recorder for MockServicesAPI.
type MockServicesAPIMockRecorder struct {
mock *MockServicesAPI
}
// NewMockServicesAPI creates a new mock instance.
func NewMockServicesAPI(ctrl *gomock.Controller) *MockServicesAPI {
mock := &MockServicesAPI{ctrl: ctrl}
mock.recorder = &MockServicesAPIMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockServicesAPI) EXPECT() *MockServicesAPIMockRecorder {
return m.recorder
}
// CreateMember mocks base method.
func (m *MockServicesAPI) CreateMember(arg0, arg1 string) (*model.TeamMember, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CreateMember", arg0, arg1)
ret0, _ := ret[0].(*model.TeamMember)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// CreateMember indicates an expected call of CreateMember.
func (mr *MockServicesAPIMockRecorder) CreateMember(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateMember", reflect.TypeOf((*MockServicesAPI)(nil).CreateMember), arg0, arg1)
}
// CreatePost mocks base method.
func (m *MockServicesAPI) CreatePost(arg0 *model.Post) (*model.Post, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CreatePost", arg0)
ret0, _ := ret[0].(*model.Post)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// CreatePost indicates an expected call of CreatePost.
func (mr *MockServicesAPIMockRecorder) CreatePost(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatePost", reflect.TypeOf((*MockServicesAPI)(nil).CreatePost), arg0)
}
// EnsureBot mocks base method.
func (m *MockServicesAPI) EnsureBot(arg0 *model.Bot) (string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EnsureBot", arg0)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EnsureBot indicates an expected call of EnsureBot.
func (mr *MockServicesAPIMockRecorder) EnsureBot(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EnsureBot", reflect.TypeOf((*MockServicesAPI)(nil).EnsureBot), arg0)
}
// GetChannelByID mocks base method.
func (m *MockServicesAPI) GetChannelByID(arg0 string) (*model.Channel, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetChannelByID", arg0)
ret0, _ := ret[0].(*model.Channel)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetChannelByID indicates an expected call of GetChannelByID.
func (mr *MockServicesAPIMockRecorder) GetChannelByID(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetChannelByID", reflect.TypeOf((*MockServicesAPI)(nil).GetChannelByID), arg0)
}
// GetChannelMember mocks base method.
func (m *MockServicesAPI) GetChannelMember(arg0, arg1 string) (*model.ChannelMember, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetChannelMember", arg0, arg1)
ret0, _ := ret[0].(*model.ChannelMember)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetChannelMember indicates an expected call of GetChannelMember.
func (mr *MockServicesAPIMockRecorder) GetChannelMember(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetChannelMember", reflect.TypeOf((*MockServicesAPI)(nil).GetChannelMember), arg0, arg1)
}
// GetChannelsForTeamForUser mocks base method.
func (m *MockServicesAPI) GetChannelsForTeamForUser(arg0, arg1 string, arg2 bool) (model.ChannelList, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetChannelsForTeamForUser", arg0, arg1, arg2)
ret0, _ := ret[0].(model.ChannelList)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetChannelsForTeamForUser indicates an expected call of GetChannelsForTeamForUser.
func (mr *MockServicesAPIMockRecorder) GetChannelsForTeamForUser(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetChannelsForTeamForUser", reflect.TypeOf((*MockServicesAPI)(nil).GetChannelsForTeamForUser), arg0, arg1, arg2)
}
// GetCloudLimits mocks base method.
func (m *MockServicesAPI) GetCloudLimits() (*model.ProductLimits, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetCloudLimits")
ret0, _ := ret[0].(*model.ProductLimits)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetCloudLimits indicates an expected call of GetCloudLimits.
func (mr *MockServicesAPIMockRecorder) GetCloudLimits() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCloudLimits", reflect.TypeOf((*MockServicesAPI)(nil).GetCloudLimits))
}
// GetConfig mocks base method.
func (m *MockServicesAPI) GetConfig() *model.Config {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetConfig")
ret0, _ := ret[0].(*model.Config)
return ret0
}
// GetConfig indicates an expected call of GetConfig.
func (mr *MockServicesAPIMockRecorder) GetConfig() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetConfig", reflect.TypeOf((*MockServicesAPI)(nil).GetConfig))
}
// GetDiagnosticID mocks base method.
func (m *MockServicesAPI) GetDiagnosticID() string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetDiagnosticID")
ret0, _ := ret[0].(string)
return ret0
}
// GetDiagnosticID indicates an expected call of GetDiagnosticID.
func (mr *MockServicesAPIMockRecorder) GetDiagnosticID() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDiagnosticID", reflect.TypeOf((*MockServicesAPI)(nil).GetDiagnosticID))
}
// GetDirectChannel mocks base method.
func (m *MockServicesAPI) GetDirectChannel(arg0, arg1 string) (*model.Channel, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetDirectChannel", arg0, arg1)
ret0, _ := ret[0].(*model.Channel)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetDirectChannel indicates an expected call of GetDirectChannel.
func (mr *MockServicesAPIMockRecorder) GetDirectChannel(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDirectChannel", reflect.TypeOf((*MockServicesAPI)(nil).GetDirectChannel), arg0, arg1)
}
// GetFileInfo mocks base method.
func (m *MockServicesAPI) GetFileInfo(arg0 string) (*model.FileInfo, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetFileInfo", arg0)
ret0, _ := ret[0].(*model.FileInfo)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetFileInfo indicates an expected call of GetFileInfo.
func (mr *MockServicesAPIMockRecorder) GetFileInfo(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFileInfo", reflect.TypeOf((*MockServicesAPI)(nil).GetFileInfo), arg0)
}
// GetLicense mocks base method.
func (m *MockServicesAPI) GetLicense() *model.License {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetLicense")
ret0, _ := ret[0].(*model.License)
return ret0
}
// GetLicense indicates an expected call of GetLicense.
func (mr *MockServicesAPIMockRecorder) GetLicense() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLicense", reflect.TypeOf((*MockServicesAPI)(nil).GetLicense))
}
// GetLogger mocks base method.
func (m *MockServicesAPI) GetLogger() mlog.LoggerIFace {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetLogger")
ret0, _ := ret[0].(mlog.LoggerIFace)
return ret0
}
// GetLogger indicates an expected call of GetLogger.
func (mr *MockServicesAPIMockRecorder) GetLogger() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLogger", reflect.TypeOf((*MockServicesAPI)(nil).GetLogger))
}
// GetMasterDB mocks base method.
func (m *MockServicesAPI) GetMasterDB() (*sql.DB, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetMasterDB")
ret0, _ := ret[0].(*sql.DB)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetMasterDB indicates an expected call of GetMasterDB.
func (mr *MockServicesAPIMockRecorder) GetMasterDB() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMasterDB", reflect.TypeOf((*MockServicesAPI)(nil).GetMasterDB))
}
// GetTeamMember mocks base method.
func (m *MockServicesAPI) GetTeamMember(arg0, arg1 string) (*model.TeamMember, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetTeamMember", arg0, arg1)
ret0, _ := ret[0].(*model.TeamMember)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetTeamMember indicates an expected call of GetTeamMember.
func (mr *MockServicesAPIMockRecorder) GetTeamMember(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTeamMember", reflect.TypeOf((*MockServicesAPI)(nil).GetTeamMember), arg0, arg1)
}
// GetUserByEmail mocks base method.
func (m *MockServicesAPI) GetUserByEmail(arg0 string) (*model.User, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetUserByEmail", arg0)
ret0, _ := ret[0].(*model.User)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetUserByEmail indicates an expected call of GetUserByEmail.
func (mr *MockServicesAPIMockRecorder) GetUserByEmail(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserByEmail", reflect.TypeOf((*MockServicesAPI)(nil).GetUserByEmail), arg0)
}
// GetUserByID mocks base method.
func (m *MockServicesAPI) GetUserByID(arg0 string) (*model.User, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetUserByID", arg0)
ret0, _ := ret[0].(*model.User)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetUserByID indicates an expected call of GetUserByID.
func (mr *MockServicesAPIMockRecorder) GetUserByID(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserByID", reflect.TypeOf((*MockServicesAPI)(nil).GetUserByID), arg0)
}
// GetUserByUsername mocks base method.
func (m *MockServicesAPI) GetUserByUsername(arg0 string) (*model.User, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetUserByUsername", arg0)
ret0, _ := ret[0].(*model.User)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetUserByUsername indicates an expected call of GetUserByUsername.
func (mr *MockServicesAPIMockRecorder) GetUserByUsername(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserByUsername", reflect.TypeOf((*MockServicesAPI)(nil).GetUserByUsername), arg0)
}
// GetUsersFromProfiles mocks base method.
func (m *MockServicesAPI) GetUsersFromProfiles(arg0 *model.UserGetOptions) ([]*model.User, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetUsersFromProfiles", arg0)
ret0, _ := ret[0].([]*model.User)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetUsersFromProfiles indicates an expected call of GetUsersFromProfiles.
func (mr *MockServicesAPIMockRecorder) GetUsersFromProfiles(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUsersFromProfiles", reflect.TypeOf((*MockServicesAPI)(nil).GetUsersFromProfiles), arg0)
}
// HasPermissionToChannel mocks base method.
func (m *MockServicesAPI) HasPermissionToChannel(arg0, arg1 string, arg2 *model.Permission) bool {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "HasPermissionToChannel", arg0, arg1, arg2)
ret0, _ := ret[0].(bool)
return ret0
}
// HasPermissionToChannel indicates an expected call of HasPermissionToChannel.
func (mr *MockServicesAPIMockRecorder) HasPermissionToChannel(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasPermissionToChannel", reflect.TypeOf((*MockServicesAPI)(nil).HasPermissionToChannel), arg0, arg1, arg2)
}
// HasPermissionToTeam mocks base method.
func (m *MockServicesAPI) HasPermissionToTeam(arg0, arg1 string, arg2 *model.Permission) bool {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "HasPermissionToTeam", arg0, arg1, arg2)
ret0, _ := ret[0].(bool)
return ret0
}
// HasPermissionToTeam indicates an expected call of HasPermissionToTeam.
func (mr *MockServicesAPIMockRecorder) HasPermissionToTeam(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasPermissionToTeam", reflect.TypeOf((*MockServicesAPI)(nil).HasPermissionToTeam), arg0, arg1, arg2)
}
// KVSetWithOptions mocks base method.
func (m *MockServicesAPI) KVSetWithOptions(arg0 string, arg1 []byte, arg2 model.PluginKVSetOptions) (bool, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "KVSetWithOptions", arg0, arg1, arg2)
ret0, _ := ret[0].(bool)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// KVSetWithOptions indicates an expected call of KVSetWithOptions.
func (mr *MockServicesAPIMockRecorder) KVSetWithOptions(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KVSetWithOptions", reflect.TypeOf((*MockServicesAPI)(nil).KVSetWithOptions), arg0, arg1, arg2)
}
// PublishPluginClusterEvent mocks base method.
func (m *MockServicesAPI) PublishPluginClusterEvent(arg0 model.PluginClusterEvent, arg1 model.PluginClusterEventSendOptions) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PublishPluginClusterEvent", arg0, arg1)
ret0, _ := ret[0].(error)
return ret0
}
// PublishPluginClusterEvent indicates an expected call of PublishPluginClusterEvent.
func (mr *MockServicesAPIMockRecorder) PublishPluginClusterEvent(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PublishPluginClusterEvent", reflect.TypeOf((*MockServicesAPI)(nil).PublishPluginClusterEvent), arg0, arg1)
}
// PublishWebSocketEvent mocks base method.
func (m *MockServicesAPI) PublishWebSocketEvent(arg0 string, arg1 map[string]interface{}, arg2 *model.WebsocketBroadcast) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "PublishWebSocketEvent", arg0, arg1, arg2)
}
// PublishWebSocketEvent indicates an expected call of PublishWebSocketEvent.
func (mr *MockServicesAPIMockRecorder) PublishWebSocketEvent(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PublishWebSocketEvent", reflect.TypeOf((*MockServicesAPI)(nil).PublishWebSocketEvent), arg0, arg1, arg2)
}
// UpdateUser mocks base method.
func (m *MockServicesAPI) UpdateUser(arg0 *model.User) (*model.User, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "UpdateUser", arg0)
ret0, _ := ret[0].(*model.User)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// UpdateUser indicates an expected call of UpdateUser.
func (mr *MockServicesAPIMockRecorder) UpdateUser(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUser", reflect.TypeOf((*MockServicesAPI)(nil).UpdateUser), arg0)
}

View File

@ -0,0 +1,70 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
//go:generate mockgen --build_flags= -destination=mocks/mockservicesapi.go -package mocks . ServicesAPI
package model
import (
"database/sql"
mm_model "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
)
type ServicesAPI interface {
// Channels service
GetDirectChannel(userID1, userID2 string) (*mm_model.Channel, error)
GetChannelByID(channelID string) (*mm_model.Channel, error)
GetChannelMember(channelID string, userID string) (*mm_model.ChannelMember, error)
GetChannelsForTeamForUser(teamID string, userID string, includeDeleted bool) (mm_model.ChannelList, error)
// Post service
CreatePost(post *mm_model.Post) (*mm_model.Post, error)
// User service
GetUserByID(userID string) (*mm_model.User, error)
GetUserByUsername(name string) (*mm_model.User, error)
GetUserByEmail(email string) (*mm_model.User, error)
UpdateUser(user *mm_model.User) (*mm_model.User, error)
GetUsersFromProfiles(options *mm_model.UserGetOptions) ([]*mm_model.User, error)
// Team service
GetTeamMember(teamID string, userID string) (*mm_model.TeamMember, error)
CreateMember(teamID string, userID string) (*mm_model.TeamMember, error)
// Permissions service
HasPermissionToTeam(userID, teamID string, permission *mm_model.Permission) bool
HasPermissionToChannel(askingUserID string, channelID string, permission *mm_model.Permission) bool
// Bot service
EnsureBot(bot *mm_model.Bot) (string, error)
// License service
GetLicense() *mm_model.License
// FileInfoStore service
GetFileInfo(fileID string) (*mm_model.FileInfo, error)
// Cluster service
PublishWebSocketEvent(event string, payload map[string]interface{}, broadcast *mm_model.WebsocketBroadcast)
PublishPluginClusterEvent(ev mm_model.PluginClusterEvent, opts mm_model.PluginClusterEventSendOptions) error
// Cloud service
GetCloudLimits() (*mm_model.ProductLimits, error)
// Config service
GetConfig() *mm_model.Config
// Logger service
GetLogger() mlog.LoggerIFace
// KVStore service
KVSetWithOptions(key string, value []byte, options mm_model.PluginKVSetOptions) (bool, error)
// Store service
GetMasterDB() (*sql.DB, error)
// System service
GetDiagnosticID() string
}

View File

@ -3,29 +3,26 @@ package server
import (
"fmt"
"github.com/mattermost/focalboard/server/model"
"github.com/mattermost/focalboard/server/services/config"
"github.com/mattermost/focalboard/server/services/notify"
"github.com/mattermost/focalboard/server/services/permissions"
"github.com/mattermost/focalboard/server/services/store"
"github.com/mattermost/focalboard/server/ws"
"github.com/mattermost/mattermost-server/v6/plugin"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
pluginapi "github.com/mattermost/mattermost-plugin-api"
)
type Params struct {
Cfg *config.Configuration
SingleUserToken string
DBStore store.Store
Logger *mlog.Logger
Logger mlog.LoggerIFace
ServerID string
WSAdapter ws.Adapter
NotifyBackends []notify.Backend
PermissionsService permissions.PermissionsService
PluginAPI plugin.API
Client *pluginapi.Client
ServicesAPI model.ServicesAPI
IsPlugin bool
}

View File

@ -53,7 +53,7 @@ type Server struct {
store store.Store
filesBackend filestore.FileBackend
telemetry *telemetry.Service
logger *mlog.Logger
logger mlog.LoggerIFace
cleanUpSessionsTask *scheduler.ScheduledTask
metricsServer *metrics.Service
metricsService *metrics.Metrics
@ -137,7 +137,7 @@ func New(params Params) (*Server, error) {
Notifications: notificationService,
Logger: params.Logger,
Permissions: params.PermissionsService,
PluginAPI: params.PluginAPI,
ServicesAPI: params.ServicesAPI,
SkipTemplateInit: utils.IsRunningUnitTests(),
}
app := app.New(params.Cfg, wsAdapter, appServices)
@ -207,7 +207,7 @@ func New(params Params) (*Server, error) {
return &server, nil
}
func NewStore(config *config.Configuration, isSingleUser bool, logger *mlog.Logger) (store.Store, error) {
func NewStore(config *config.Configuration, isSingleUser bool, logger mlog.LoggerIFace) (store.Store, error) {
sqlDB, err := sql.Open(config.DBType, config.DBConfigString)
if err != nil {
logger.Error("connectDatabase failed", mlog.Err(err))
@ -350,7 +350,7 @@ func (s *Server) Config() *config.Configuration {
return s.config
}
func (s *Server) Logger() *mlog.Logger {
func (s *Server) Logger() mlog.LoggerIFace {
return s.logger
}
@ -418,7 +418,7 @@ type telemetryOptions struct {
cfg *config.Configuration
telemetryID string
serverID string
logger *mlog.Logger
logger mlog.LoggerIFace
singleUser bool
}
@ -494,7 +494,7 @@ func initTelemetry(opts telemetryOptions) *telemetry.Service {
return telemetryService
}
func initNotificationService(backends []notify.Backend, logger *mlog.Logger) (*notify.Service, error) {
func initNotificationService(backends []notify.Backend, logger mlog.LoggerIFace) (*notify.Service, error) {
loggerBackend := notifylogger.New(logger, mlog.LvlDebug)
backends = append(backends, loggerBackend)

View File

@ -15,7 +15,7 @@ type Service struct {
}
// NewMetricsServer factory method to create a new prometheus server.
func NewMetricsServer(address string, metricsService *Metrics, logger *mlog.Logger) *Service {
func NewMetricsServer(address string, metricsService *Metrics, logger mlog.LoggerIFace) *Service {
return &Service{
&http.Server{
Addr: address,

View File

@ -14,11 +14,11 @@ const (
)
type Backend struct {
logger *mlog.Logger
logger mlog.LoggerIFace
level mlog.Level
}
func New(logger *mlog.Logger, level mlog.Level) *Backend {
func New(logger mlog.LoggerIFace, level mlog.Level) *Backend {
return &Backend{
logger: logger,
level: level,

View File

@ -32,7 +32,7 @@ type BackendParams struct {
AppAPI AppAPI
Permissions permissions.PermissionsService
Delivery MentionDelivery
Logger *mlog.Logger
Logger mlog.LoggerIFace
}
// Backend provides the notification backend for @mentions.
@ -40,7 +40,7 @@ type Backend struct {
appAPI AppAPI
permissions permissions.PermissionsService
delivery MentionDelivery
logger *mlog.Logger
logger mlog.LoggerIFace
mux sync.RWMutex
listeners []MentionListener
@ -150,7 +150,7 @@ func (b *Backend) BlockChanged(evt notify.BlockChangeEvent) error {
return merr.ErrorOrNil()
}
func safeCallListener(listener MentionListener, userID string, evt notify.BlockChangeEvent, logger *mlog.Logger) {
func safeCallListener(listener MentionListener, userID string, evt notify.BlockChangeEvent, logger mlog.LoggerIFace) {
// don't let panicky listeners stop notifications
defer func() {
if r := recover(); r != nil {

View File

@ -52,7 +52,7 @@ type diffGenerator struct {
store AppAPI
hint *model.NotificationHint
lastNotifyAt int64
logger *mlog.Logger
logger mlog.LoggerIFace
}
func (dg *diffGenerator) generateDiffs() ([]*Diff, error) {

View File

@ -8,7 +8,7 @@ import (
"github.com/mattermost/mattermost-server/v6/shared/mlog"
)
func generateMarkdownDiff(oldText string, newText string, logger *mlog.Logger) string {
func generateMarkdownDiff(oldText string, newText string, logger mlog.LoggerIFace) string {
oldTxtNorm := normalizeText(oldText)
newTxtNorm := normalizeText(newText)

View File

@ -36,7 +36,7 @@ type DiffConvOpts struct {
Language string
MakeCardLink func(block *model.Block, board *model.Board, card *model.Block) string
MakeBoardLink func(board *model.Board) string
Logger *mlog.Logger
Logger mlog.LoggerIFace
}
// getTemplate returns a new or cached named template based on the language specified.

View File

@ -35,7 +35,7 @@ type notifier struct {
store AppAPI
permissions permissions.PermissionsService
delivery SubscriptionDelivery
logger *mlog.Logger
logger mlog.LoggerIFace
hints chan *model.NotificationHint

View File

@ -24,7 +24,7 @@ type BackendParams struct {
AppAPI AppAPI
Permissions permissions.PermissionsService
Delivery SubscriptionDelivery
Logger *mlog.Logger
Logger mlog.LoggerIFace
NotifyFreqCardSeconds int
NotifyFreqBoardSeconds int
}
@ -35,7 +35,7 @@ type Backend struct {
permissions permissions.PermissionsService
delivery SubscriptionDelivery
notifier *notifier
logger *mlog.Logger
logger mlog.LoggerIFace
notifyFreqCardSeconds int
notifyFreqBoardSeconds int
}

View File

@ -31,5 +31,10 @@ func (pd *PluginDelivery) MentionDeliver(mentionedUser *mm_model.User, extract s
ChannelId: channel.Id,
Message: formatMessage(author.Username, extract, evt.Card.Title, link, evt.BlockChanged, boardLink, evt.Board.Title),
}
return mentionedUser.Id, pd.api.CreatePost(post)
if _, err := pd.api.CreatePost(post); err != nil {
return "", err
}
return mentionedUser.Id, nil
}

View File

@ -7,13 +7,13 @@ import (
mm_model "github.com/mattermost/mattermost-server/v6/model"
)
type PluginAPI interface {
type servicesAPI interface {
// GetDirectChannel gets a direct message channel.
// If the channel does not exist it will create it.
GetDirectChannel(userID1, userID2 string) (*mm_model.Channel, error)
// CreatePost creates a post.
CreatePost(post *mm_model.Post) error
CreatePost(post *mm_model.Post) (*mm_model.Post, error)
// GetUserByID gets a user by their ID.
GetUserByID(userID string) (*mm_model.User, error)
@ -39,11 +39,11 @@ type PluginAPI interface {
type PluginDelivery struct {
botID string
serverRoot string
api PluginAPI
api servicesAPI
}
// New creates a PluginDelivery instance.
func New(botID string, serverRoot string, api PluginAPI) *PluginDelivery {
func New(botID string, serverRoot string, api servicesAPI) *PluginDelivery {
return &PluginDelivery{
botID: botID,
serverRoot: serverRoot,

View File

@ -41,7 +41,8 @@ func (pd *PluginDelivery) SubscriptionDeliverSlackAttachments(teamID string, sub
mm_model.ParseSlackAttachment(post, attachments)
return pd.api.CreatePost(post)
_, err = pd.api.CreatePost(post)
return err
}
func (pd *PluginDelivery) getDirectChannelID(teamID string, subscriberID string, subscriberType model.SubscriberType, botID string) (string, error) {

View File

@ -45,8 +45,8 @@ var (
)
func Test_userByUsername(t *testing.T) {
pluginAPI := newPlugAPIMock(mockUsers)
delivery := New("bot_id", "server_root", pluginAPI)
servicesAPI := newServicesAPIMock(mockUsers)
delivery := New("bot_id", "server_root", servicesAPI)
tests := []struct {
name string
@ -79,17 +79,17 @@ func Test_userByUsername(t *testing.T) {
}
}
type pluginAPIMock struct {
type servicesAPIMock struct {
users map[string]*mm_model.User
}
func newPlugAPIMock(users map[string]*mm_model.User) pluginAPIMock {
return pluginAPIMock{
func newServicesAPIMock(users map[string]*mm_model.User) servicesAPIMock {
return servicesAPIMock{
users: users,
}
}
func (m pluginAPIMock) GetUserByUsername(name string) (*mm_model.User, error) {
func (m servicesAPIMock) GetUserByUsername(name string) (*mm_model.User, error) {
user, ok := m.users[name]
if !ok {
return nil, model.NewErrNotFound(name)
@ -97,15 +97,15 @@ func (m pluginAPIMock) GetUserByUsername(name string) (*mm_model.User, error) {
return user, nil
}
func (m pluginAPIMock) GetDirectChannel(userID1, userID2 string) (*mm_model.Channel, error) {
func (m servicesAPIMock) GetDirectChannel(userID1, userID2 string) (*mm_model.Channel, error) {
return nil, nil
}
func (m pluginAPIMock) CreatePost(post *mm_model.Post) error {
return nil
func (m servicesAPIMock) CreatePost(post *mm_model.Post) (*mm_model.Post, error) {
return post, nil
}
func (m pluginAPIMock) GetUserByID(userID string) (*mm_model.User, error) {
func (m servicesAPIMock) GetUserByID(userID string) (*mm_model.User, error) {
for _, user := range m.users {
if user.Id == userID {
return user, nil
@ -114,7 +114,7 @@ func (m pluginAPIMock) GetUserByID(userID string) (*mm_model.User, error) {
return nil, model.NewErrNotFound(userID)
}
func (m pluginAPIMock) GetTeamMember(teamID string, userID string) (*mm_model.TeamMember, error) {
func (m servicesAPIMock) GetTeamMember(teamID string, userID string) (*mm_model.TeamMember, error) {
user, err := m.GetUserByID(userID)
if err != nil {
return nil, err
@ -131,15 +131,15 @@ func (m pluginAPIMock) GetTeamMember(teamID string, userID string) (*mm_model.Te
return member, nil
}
func (m pluginAPIMock) GetChannelByID(channelID string) (*mm_model.Channel, error) {
func (m servicesAPIMock) GetChannelByID(channelID string) (*mm_model.Channel, error) {
return nil, model.NewErrNotFound(channelID)
}
func (m pluginAPIMock) GetChannelMember(channelID string, userID string) (*mm_model.ChannelMember, error) {
func (m servicesAPIMock) GetChannelMember(channelID string, userID string) (*mm_model.ChannelMember, error) {
return nil, model.NewErrNotFound(userID)
}
func (m pluginAPIMock) CreateMember(teamID string, userID string) (*mm_model.TeamMember, error) {
func (m servicesAPIMock) CreateMember(teamID string, userID string) (*mm_model.TeamMember, error) {
member := &mm_model.TeamMember{
UserId: userID,
TeamId: teamID,

View File

@ -42,11 +42,11 @@ type Backend interface {
type Service struct {
mux sync.RWMutex
backends []Backend
logger *mlog.Logger
logger mlog.LoggerIFace
}
// New creates a notification service with one or more Backends capable of sending notifications.
func New(logger *mlog.Logger, backends ...Backend) (*Service, error) {
func New(logger mlog.LoggerIFace, backends ...Backend) (*Service, error) {
notify := &Service{
backends: make([]Backend, 0, len(backends)),
logger: logger,

View File

@ -13,10 +13,10 @@ import (
type Service struct {
store permissions.Store
logger *mlog.Logger
logger mlog.LoggerIFace
}
func New(store permissions.Store, logger *mlog.Logger) *Service {
func New(store permissions.Store, logger mlog.LoggerIFace) *Service {
return &Service{
store: store,
logger: logger,

View File

@ -11,6 +11,7 @@ import (
permissionsMocks "github.com/mattermost/focalboard/server/services/permissions/mocks"
mmModel "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
@ -34,7 +35,7 @@ func SetupTestHelper(t *testing.T) *TestHelper {
ctrl: ctrl,
store: mockStore,
api: mockAPI,
permissions: New(mockStore, mockAPI),
permissions: New(mockStore, mockAPI, mlog.CreateConsoleTestLogger(true, mlog.LvlError)),
}
}

View File

@ -8,20 +8,21 @@ import (
"github.com/mattermost/focalboard/server/services/permissions"
mmModel "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
)
type APIInterface interface {
HasPermissionToTeam(userID string, teamID string, permission *mmModel.Permission) bool
HasPermissionToChannel(userID string, channelID string, permission *mmModel.Permission) bool
LogError(string, ...interface{})
}
type Service struct {
store permissions.Store
api APIInterface
store permissions.Store
api APIInterface
logger mlog.LoggerIFace
}
func New(store permissions.Store, api APIInterface) *Service {
func New(store permissions.Store, api APIInterface, logger mlog.LoggerIFace) *Service {
return &Service{
store: store,
api: api,
@ -59,10 +60,10 @@ func (s *Service) HasPermissionToBoard(userID, boardID string, permission *mmMod
}
board = boards[0]
} else if err != nil {
s.api.LogError("error getting board",
"boardID", boardID,
"userID", userID,
"error", err,
s.logger.Error("error getting board",
mlog.String("boardID", boardID),
mlog.String("userID", userID),
mlog.Err(err),
)
return false
}
@ -78,10 +79,10 @@ func (s *Service) HasPermissionToBoard(userID, boardID string, permission *mmMod
return false
}
if err != nil {
s.api.LogError("error getting member for board",
"boardID", boardID,
"userID", userID,
"error", err,
s.logger.Error("error getting member for board",
mlog.String("boardID", boardID),
mlog.String("userID", userID),
mlog.Err(err),
)
return false
}

View File

@ -3,13 +3,11 @@ package mattermostauthlayer
import (
"database/sql"
"encoding/json"
"errors"
"net/http"
"strings"
pluginapi "github.com/mattermost/mattermost-plugin-api"
mmModel "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/plugin"
sq "github.com/Masterminds/squirrel"
@ -25,35 +23,43 @@ var systemsBot = &mmModel.Bot{
DisplayName: "System",
}
// servicesAPI is the interface required my the MattermostAuthLayer to interact with
// the mattermost-server. You can use plugin-api or product-api adapter implementations.
type servicesAPI interface {
GetDirectChannel(userID1, userID2 string) (*mmModel.Channel, error)
GetChannelByID(channelID string) (*mmModel.Channel, error)
GetChannelMember(channelID string, userID string) (*mmModel.ChannelMember, error)
GetChannelsForTeamForUser(teamID string, userID string, includeDeleted bool) (mmModel.ChannelList, error)
GetUserByID(userID string) (*mmModel.User, error)
UpdateUser(user *mmModel.User) (*mmModel.User, error)
GetUserByEmail(email string) (*mmModel.User, error)
GetUserByUsername(username string) (*mmModel.User, error)
GetLicense() *mmModel.License
GetFileInfo(fileID string) (*mmModel.FileInfo, error)
GetCloudLimits() (*mmModel.ProductLimits, error)
EnsureBot(bot *mmModel.Bot) (string, error)
CreatePost(post *mmModel.Post) (*mmModel.Post, error)
}
// Store represents the abstraction of the data storage.
type MattermostAuthLayer struct {
store.Store
dbType string
mmDB *sql.DB
logger *mlog.Logger
pluginAPI plugin.API
logger mlog.LoggerIFace
servicesAPI servicesAPI
tablePrefix string
client *pluginapi.Client
}
// New creates a new SQL implementation of the store.
func New(
dbType string,
db *sql.DB,
store store.Store,
logger *mlog.Logger,
pluginAPI plugin.API,
tablePrefix string,
client *pluginapi.Client,
) (*MattermostAuthLayer, error) {
func New(dbType string, db *sql.DB, store store.Store, logger mlog.LoggerIFace, api servicesAPI, tablePrefix string) (*MattermostAuthLayer, error) {
layer := &MattermostAuthLayer{
Store: store,
dbType: dbType,
mmDB: db,
logger: logger,
pluginAPI: pluginAPI,
servicesAPI: api,
tablePrefix: tablePrefix,
client: client,
}
return layer, nil
@ -82,7 +88,7 @@ func (s *MattermostAuthLayer) GetRegisteredUserCount() (int, error) {
}
func (s *MattermostAuthLayer) GetUserByID(userID string) (*model.User, error) {
mmuser, err := s.pluginAPI.GetUser(userID)
mmuser, err := s.servicesAPI.GetUserByID(userID)
if err != nil {
return nil, err
}
@ -91,7 +97,7 @@ func (s *MattermostAuthLayer) GetUserByID(userID string) (*model.User, error) {
}
func (s *MattermostAuthLayer) GetUserByEmail(email string) (*model.User, error) {
mmuser, err := s.pluginAPI.GetUserByEmail(email)
mmuser, err := s.servicesAPI.GetUserByEmail(email)
if err != nil {
return nil, err
}
@ -100,7 +106,7 @@ func (s *MattermostAuthLayer) GetUserByEmail(email string) (*model.User, error)
}
func (s *MattermostAuthLayer) GetUserByUsername(username string) (*model.User, error) {
mmuser, err := s.pluginAPI.GetUserByUsername(username)
mmuser, err := s.servicesAPI.GetUserByUsername(username)
if err != nil {
return nil, err
}
@ -125,7 +131,7 @@ func (s *MattermostAuthLayer) UpdateUserPasswordByID(userID, password string) er
}
func (s *MattermostAuthLayer) PatchUserProps(userID string, patch model.UserPropPatch) error {
user, err := s.pluginAPI.GetUser(userID)
user, err := s.servicesAPI.GetUserByID(userID)
if err != nil {
s.logger.Error("failed to fetch user", mlog.String("userID", userID), mlog.Err(err))
return err
@ -143,7 +149,7 @@ func (s *MattermostAuthLayer) PatchUserProps(userID string, patch model.UserProp
user.Props = props
if _, err := s.pluginAPI.UpdateUser(user); err != nil {
if _, err := s.servicesAPI.UpdateUser(user); err != nil {
s.logger.Error("failed to update user", mlog.String("userID", userID), mlog.Err(err))
return err
}
@ -366,7 +372,7 @@ func (s *MattermostAuthLayer) CloseRows(rows *sql.Rows) {
func (s *MattermostAuthLayer) CreatePrivateWorkspace(userID string) (string, error) {
// we emulate a private workspace by creating
// a DM channel from the user to themselves.
channel, err := s.pluginAPI.GetDirectChannel(userID, userID)
channel, err := s.servicesAPI.GetDirectChannel(userID, userID)
if err != nil {
s.logger.Error("error fetching private workspace", mlog.String("userID", userID), mlog.Err(err))
return "", err
@ -406,17 +412,23 @@ func mmUserToFbUser(mmUser *mmModel.User) model.User {
}
func (s *MattermostAuthLayer) GetFileInfo(id string) (*mmModel.FileInfo, error) {
fileInfo, appErr := s.pluginAPI.GetFileInfo(id)
if appErr != nil {
fileInfo, err := s.servicesAPI.GetFileInfo(id)
if err != nil {
// Not finding fileinfo is fine because we don't have data for
// any existing files already uploaded in Boards before this code
// was deployed.
if appErr.StatusCode == http.StatusNotFound {
return nil, nil
var appErr *mmModel.AppError
if errors.As(err, &appErr) {
if appErr.StatusCode == http.StatusNotFound {
return nil, nil
}
}
s.logger.Error("error fetching fileinfo", mlog.String("id", id), mlog.Err(appErr))
return nil, appErr
s.logger.Error("error fetching fileinfo",
mlog.String("id", id),
mlog.Err(err),
)
return nil, err
}
return fileInfo, nil
@ -484,7 +496,7 @@ func (s *MattermostAuthLayer) SaveFileInfo(fileInfo *mmModel.FileInfo) error {
}
func (s *MattermostAuthLayer) GetLicense() *mmModel.License {
return s.pluginAPI.GetLicense()
return s.servicesAPI.GetLicense()
}
func boardFields(prefix string) []string {
@ -621,7 +633,7 @@ func (s *MattermostAuthLayer) boardsFromRows(rows *sql.Rows) ([]*model.Board, er
}
func (s *MattermostAuthLayer) GetCloudLimits() (*mmModel.ProductLimits, error) {
return s.pluginAPI.GetCloudLimits()
return s.servicesAPI.GetCloudLimits()
}
func (s *MattermostAuthLayer) implicitBoardMembershipsFromRows(rows *sql.Rows) ([]*model.BoardMember, error) {
@ -646,6 +658,7 @@ func (s *MattermostAuthLayer) implicitBoardMembershipsFromRows(rows *sql.Rows) (
return boardMembers, nil
}
func (s *MattermostAuthLayer) GetMemberForBoard(boardID, userID string) (*model.BoardMember, error) {
bm, err := s.Store.GetMemberForBoard(boardID, userID)
if model.IsErrNotFound(err) {
@ -654,7 +667,7 @@ func (s *MattermostAuthLayer) GetMemberForBoard(boardID, userID string) (*model.
return nil, err
}
if b.ChannelID != "" {
_, err := s.pluginAPI.GetChannelMember(b.ChannelID, userID)
_, err := s.servicesAPI.GetChannelMember(b.ChannelID, userID)
if err != nil {
return nil, err
}
@ -772,7 +785,7 @@ func (s *MattermostAuthLayer) GetBoardsForUserAndTeam(userID, teamID string) ([]
}
func (s *MattermostAuthLayer) SearchUserChannels(teamID, userID, query string) ([]*mmModel.Channel, error) {
channels, err := s.pluginAPI.GetChannelsForTeamForUser(teamID, userID, false)
channels, err := s.servicesAPI.GetChannelsForTeamForUser(teamID, userID, false)
if err != nil {
return nil, err
}
@ -794,7 +807,7 @@ func (s *MattermostAuthLayer) SearchUserChannels(teamID, userID, query string) (
}
func (s *MattermostAuthLayer) GetChannel(teamID, channelID string) (*mmModel.Channel, error) {
channel, err := s.pluginAPI.GetChannel(channelID)
channel, err := s.servicesAPI.GetChannelByID(channelID)
if err != nil {
return nil, err
}
@ -802,7 +815,7 @@ func (s *MattermostAuthLayer) GetChannel(teamID, channelID string) (*mmModel.Cha
}
func (s *MattermostAuthLayer) getSystemBotID() (string, error) {
botID, err := s.client.Bot.EnsureBot(systemsBot)
botID, err := s.servicesAPI.EnsureBot(systemsBot)
if err != nil {
s.logger.Error("failed to ensure system bot", mlog.String("username", systemsBot.Username), mlog.Err(err))
return "", err
@ -818,7 +831,7 @@ func (s *MattermostAuthLayer) SendMessage(message, postType string, receipts []s
}
for _, receipt := range receipts {
channel, err := s.pluginAPI.GetDirectChannel(botID, receipt)
channel, err := s.servicesAPI.GetDirectChannel(botID, receipt)
if err != nil {
s.logger.Error(
"failed to get DM channel between system bot and user for receipt",
@ -836,7 +849,7 @@ func (s *MattermostAuthLayer) SendMessage(message, postType string, receipts []s
Type: postType,
}
if _, err := s.pluginAPI.CreatePost(post); err != nil {
if _, err := s.servicesAPI.CreatePost(post); err != nil {
s.logger.Error(
"failed to send message to receipt from SendMessage",
mlog.String("receipt", receipt),

View File

@ -420,15 +420,23 @@ func (s *SQLStore) getBestTeamForBoard(tx sq.BaseRunner, board *model.Board) (st
// no common teams found. Let's try finding the best suitable team
if board.Type == "D" {
// get DM's creator and pick one of their team
channel, appErr := (*s.pluginAPI).GetChannel(board.ChannelID)
if appErr != nil {
s.logger.Error("failed to fetch DM channel for board", mlog.String("board_id", board.ID), mlog.String("channel_id", board.ChannelID), mlog.Err(appErr))
return "", appErr
channel, err := (s.servicesAPI).GetChannelByID(board.ChannelID)
if err != nil {
s.logger.Error("failed to fetch DM channel for board",
mlog.String("board_id", board.ID),
mlog.String("channel_id", board.ChannelID),
mlog.Err(err),
)
return "", err
}
if _, ok := userTeams[channel.CreatorId]; !ok {
s.logger.Error("channel creator not found in user teams",
mlog.String("board_id", board.ID),
mlog.String("channel_id", board.ChannelID),
mlog.String("creator_id", channel.CreatorId),
)
err := fmt.Errorf("%w board_id: %s, channel_id: %s, creator_id: %s", errChannelCreatorNotInTeam, board.ID, board.ChannelID, channel.CreatorId)
s.logger.Error(err.Error())
return "", err
}

View File

@ -4,21 +4,27 @@ import (
"database/sql"
"fmt"
"github.com/mattermost/mattermost-server/v6/plugin"
mmModel "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
)
// servicesAPI is the interface required my the Params to interact with the mattermost-server.
// You can use plugin-api or product-api adapter implementations.
type servicesAPI interface {
GetChannelByID(string) (*mmModel.Channel, error)
}
type Params struct {
DBType string
ConnectionString string
TablePrefix string
Logger *mlog.Logger
Logger mlog.LoggerIFace
DB *sql.DB
IsPlugin bool
IsSingleUser bool
NewMutexFn MutexFactory
PluginAPI *plugin.API
ServicesAPI servicesAPI
}
func (p Params) CheckValid() error {

View File

@ -4,8 +4,6 @@ import (
"database/sql"
"net/url"
"github.com/mattermost/mattermost-server/v6/plugin"
sq "github.com/Masterminds/squirrel"
"github.com/mattermost/focalboard/server/model"
@ -24,9 +22,9 @@ type SQLStore struct {
connectionString string
isPlugin bool
isSingleUser bool
logger *mlog.Logger
logger mlog.LoggerIFace
NewMutexFn MutexFactory
pluginAPI *plugin.API
servicesAPI servicesAPI
isBinaryParam bool
}
@ -51,7 +49,7 @@ func New(params Params) (*SQLStore, error) {
isPlugin: params.IsPlugin,
isSingleUser: params.IsSingleUser,
NewMutexFn: params.NewMutexFn,
pluginAPI: params.PluginAPI,
servicesAPI: params.ServicesAPI,
}
var err error

View File

@ -27,7 +27,7 @@ type Tracker map[string]interface{}
type Service struct {
trackers map[string]TrackerFunc
logger *mlog.Logger
logger mlog.LoggerIFace
rudderClient rudder.Client
telemetryID string
timestampLastTelemetrySent time.Time
@ -38,7 +38,7 @@ type RudderConfig struct {
DataplaneURL string
}
func New(telemetryID string, logger *mlog.Logger) *Service {
func New(telemetryID string, logger mlog.LoggerIFace) *Service {
service := &Service{
logger: logger,
telemetryID: telemetryID,

View File

@ -34,11 +34,11 @@ func (wh *Client) NotifyUpdate(block model.Block) {
// Client is a webhook client.
type Client struct {
config *config.Configuration
logger *mlog.Logger
logger mlog.LoggerIFace
}
// NewClient creates a new Client.
func NewClient(config *config.Configuration, logger *mlog.Logger) *Client {
func NewClient(config *config.Configuration, logger mlog.LoggerIFace) *Client {
return &Client{
config: config,
logger: logger,

View File

@ -26,11 +26,11 @@ type CallbackQueue struct {
idone uint32
logger *mlog.Logger
logger mlog.LoggerIFace
}
// NewCallbackQueue creates a new CallbackQueue and starts a thread pool to service it.
func NewCallbackQueue(name string, queueSize int, poolSize int, logger *mlog.Logger) *CallbackQueue {
func NewCallbackQueue(name string, queueSize int, poolSize int, logger mlog.LoggerIFace) *CallbackQueue {
cn := &CallbackQueue{
name: name,
poolSize: poolSize,

View File

@ -32,11 +32,11 @@ type Server struct {
basePrefix string
port int
ssl bool
logger *mlog.Logger
logger mlog.LoggerIFace
}
// NewServer creates a new instance of the webserver.
func NewServer(rootPath string, serverRoot string, port int, ssl, localOnly bool, logger *mlog.Logger) *Server {
func NewServer(rootPath string, serverRoot string, port int, ssl, localOnly bool, logger mlog.LoggerIFace) *Server {
r := mux.NewRouter()
basePrefix := os.Getenv("FOCALBOARD_HTTP_SERVER_BASEPATH")

View File

@ -3,8 +3,9 @@ package web
import (
"testing"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
"github.com/stretchr/testify/require"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
)
func Test_NewServer(t *testing.T) {
@ -15,7 +16,7 @@ func Test_NewServer(t *testing.T) {
ssl bool
port int
localOnly bool
logger *mlog.Logger
logger mlog.LoggerIFace
expectedBaseURL string
expectedServerAddr string
}{

View File

@ -13,7 +13,6 @@ import (
"github.com/mattermost/focalboard/server/utils"
mmModel "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/plugin"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
)
@ -35,11 +34,11 @@ type PluginAdapterInterface interface {
}
type PluginAdapter struct {
api plugin.API
api servicesAPI
auth auth.AuthInterface
staleThreshold time.Duration
store Store
logger *mlog.Logger
logger mlog.LoggerIFace
listenersMU sync.RWMutex
listeners map[string]*PluginAdapterClient
@ -50,7 +49,14 @@ type PluginAdapter struct {
listenersByBlock map[string][]*PluginAdapterClient
}
func NewPluginAdapter(api plugin.API, auth auth.AuthInterface, store Store, logger *mlog.Logger) *PluginAdapter {
// servicesAPI is the interface required by the PluginAdapter to interact with
// the mattermost-server.
type servicesAPI interface {
PublishWebSocketEvent(event string, payload map[string]interface{}, broadcast *mmModel.WebsocketBroadcast)
PublishPluginClusterEvent(ev mmModel.PluginClusterEvent, opts mmModel.PluginClusterEventSendOptions) error
}
func NewPluginAdapter(api servicesAPI, auth auth.AuthInterface, store Store, logger mlog.LoggerIFace) *PluginAdapter {
return &PluginAdapter{
api: api,
auth: auth,

View File

@ -4,6 +4,7 @@ import (
"encoding/json"
mmModel "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
)
type ClusterMessage struct {
@ -16,9 +17,9 @@ type ClusterMessage struct {
func (pa *PluginAdapter) sendMessageToCluster(id string, clusterMessage *ClusterMessage) {
b, err := json.Marshal(clusterMessage)
if err != nil {
pa.api.LogError("couldn't get JSON bytes from cluster message",
"id", id,
"err", err,
pa.logger.Error("couldn't get JSON bytes from cluster message",
mlog.String("id", id),
mlog.Err(err),
)
return
}
@ -29,21 +30,21 @@ func (pa *PluginAdapter) sendMessageToCluster(id string, clusterMessage *Cluster
}
if err := pa.api.PublishPluginClusterEvent(event, opts); err != nil {
pa.api.LogError("error publishing cluster event",
"id", id,
"err", err,
pa.logger.Error("error publishing cluster event",
mlog.String("id", id),
mlog.Err(err),
)
}
}
func (pa *PluginAdapter) HandleClusterEvent(ev mmModel.PluginClusterEvent) {
pa.api.LogDebug("received cluster event", "id", ev.Id)
pa.logger.Debug("received cluster event", mlog.String("id", ev.Id))
var clusterMessage ClusterMessage
if err := json.Unmarshal(ev.Data, &clusterMessage); err != nil {
pa.api.LogError("cannot unmarshal cluster message data",
"id", ev.Id,
"err", err,
pa.logger.Error("cannot unmarshal cluster message data",
mlog.String("id", ev.Id),
mlog.Err(err),
)
return
}
@ -61,9 +62,9 @@ func (pa *PluginAdapter) HandleClusterEvent(ev mmModel.PluginClusterEvent) {
}
if action == "" {
// no action was specified in the event; assume block change and warn.
pa.api.LogWarn("cannot determine action from cluster message data",
"id", ev.Id,
"payload", clusterMessage.Payload,
pa.logger.Warn("cannot determine action from cluster message data",
mlog.String("id", ev.Id),
mlog.Map("payload", clusterMessage.Payload),
)
return
}

View File

@ -51,7 +51,7 @@ type Server struct {
auth *auth.Auth
singleUserToken string
isMattermostAuth bool
logger *mlog.Logger
logger mlog.LoggerIFace
store Store
}
@ -68,7 +68,7 @@ func (wss *websocketSession) isAuthenticated() bool {
}
// NewServer creates a new Server.
func NewServer(auth *auth.Auth, singleUserToken string, isMattermostAuth bool, logger *mlog.Logger, store Store) *Server {
func NewServer(auth *auth.Auth, singleUserToken string, isMattermostAuth bool, logger mlog.LoggerIFace, store Store) *Server {
return &Server{
listeners: make(map[*websocketSession]bool),
listenersByTeam: make(map[string][]*websocketSession),