From 12341e503312cf15a0bb5f33637a8552e7cf2d98 Mon Sep 17 00:00:00 2001 From: Sean Sackowitz Date: Thu, 21 Jun 2018 17:07:40 -0400 Subject: [PATCH] Initial --- .gitignore | 28 +++++++ LICENSE | 201 ++++++++++++++++++++++++++++++++++++++++++++++ Makefile | 89 ++++++++++++++++++++ README.md | 9 +++ plugin.json | 13 +++ server/Gopkg.lock | 133 ++++++++++++++++++++++++++++++ server/Gopkg.toml | 11 +++ server/config.go | 5 ++ server/main.go | 21 +++++ server/plugin.go | 85 ++++++++++++++++++++ 10 files changed, 595 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 plugin.json create mode 100644 server/Gopkg.lock create mode 100644 server/Gopkg.toml create mode 100644 server/config.go create mode 100644 server/main.go create mode 100644 server/plugin.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4246fda --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +# Binaries for programs and plugins +*.exe +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 +.glide/ + +# Build +/coverage.txt +/plugin.exe +/mattermost-zoom-plugin*.tar.gz +/dist +server/vendor +node_modules +.npminstall +webapp/dist + +# Mac +*.swp +.DS_Store \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..506ced8 --- /dev/null +++ b/Makefile @@ -0,0 +1,89 @@ +.PHONY: build test run clean stop check-style gofmt dist + +MKFILE_PATH=$(abspath $(lastword $(MAKEFILE_LIST))) +CURRENT_DIR_NAME=$(notdir $(patsubst %/,%,$(dir $(MKFILE_PATH)))) +PLUGIN_NAME=$(CURRENT_DIR_NAME) +GOOS=$(shell uname -s | tr '[:upper:]' '[:lower:]') +GOARCH=amd64 + +all: dist + +check-style: gofmt + @echo Checking for style guide compliance + +gofmt: + @echo Running GOFMT + + @for package in $$(go list ./server/...); do \ + echo "Checking "$$package; \ + files=$$(go list -f '{{range .GoFiles}}{{$$.Dir}}/{{.}} {{end}}' $$package); \ + if [ "$$files" ]; then \ + gofmt_output=$$(gofmt -d -s $$files 2>&1); \ + if [ "$$gofmt_output" ]; then \ + echo "$$gofmt_output"; \ + echo "gofmt failure"; \ + exit 1; \ + fi; \ + fi; \ + done + @echo "gofmt success"; \ + +test: + go test -v -coverprofile=coverage.txt ./... + +vendor: server/Gopkg.lock + @echo Run this to updated the go lang dependencies after a major release + cd server && dep ensure -update + +dist: check-style + @echo Building plugin + + # Clean old dist + rm -rf dist + rm -rf webapp/dist + rm -f server/plugin.exe + + # Build files from server + cd server && go get github.com/mitchellh/gox + $(shell go env GOPATH)/bin/gox -osarch='darwin/amd64 linux/amd64 windows/amd64' -output 'dist/intermediate/plugin_{{.OS}}_{{.Arch}}' ./server + + # Copy plugin files + mkdir -p dist/$(PLUGIN_NAME)/ + cp plugin.json dist/$(PLUGIN_NAME)/ + + # Copy server executables & compress plugin + mkdir -p dist/$(PLUGIN_NAME)/server + mv dist/intermediate/plugin_darwin_amd64 dist/$(PLUGIN_NAME)/server/plugin.exe + cd dist && tar -zcvf $(PLUGIN_NAME)-darwin-amd64.tar.gz $(PLUGIN_NAME)/* + mv dist/intermediate/plugin_linux_amd64 dist/$(PLUGIN_NAME)/server/plugin.exe + cd dist && tar -zcvf $(PLUGIN_NAME)-linux-amd64.tar.gz $(PLUGIN_NAME)/* + mv dist/intermediate/plugin_windows_amd64.exe dist/$(PLUGIN_NAME)/server/plugin.exe + cd dist && tar -zcvf $(PLUGIN_NAME)-windows-amd64.tar.gz $(PLUGIN_NAME)/* + + # Clean up temp files + rm -rf dist/$(PLUGIN_NAME) + rm -rf dist/intermediate + + @echo MacOS X plugin built at: dist/$(PLUGIN_NAME)-darwin-amd64.tar.gz + @echo Linux plugin built at: dist/$(PLUGIN_NAME)-linux-amd64.tar.gz + @echo Windows plugin built at: dist/$(PLUGIN_NAME)-windows-amd64.tar.gz + +deploy: dist + cp dist/$(PLUGIN_NAME)-$(GOOS)-$(GOARCH).tar.gz ../mattermost-server/plugins/ + rm -rf ../mattermost-server/plugins/$(PLUGIN_NAME) + tar -C ../mattermost-server/plugins/ -zxvf ../mattermost-server/plugins/$(PLUGIN_NAME)-$(GOOS)-$(GOARCH).tar.gz + +run: .npminstall + @echo Not yet implemented + +stop: + @echo Not yet implemented + +clean: + @echo Cleaning plugin + + rm -rf dist + rm -rf webapp/dist + rm -rf webapp/node_modules + rm -rf webapp/.npminstall + rm -f server/plugin.exe \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..b4b7c06 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# Gyazo Plugin + +Messages posted with a gyazo link will have custom formatting applied. + +## Installation + +1. Go to the [releases page of this Github repository](https://github.com/seansackowitz/mattermost-plugin-gyazo) and download the latest release for your Mattermost server. +2. Upload this file in the Mattermost **System Console > Plugins > Management** page to install the plugin. To learn more about how to upload a plugin, [see the documentation](https://docs.mattermost.com/administration/plugins.html#plugin-uploads). +3. Post some gyazo links. \ No newline at end of file diff --git a/plugin.json b/plugin.json new file mode 100644 index 0000000..92e94ca --- /dev/null +++ b/plugin.json @@ -0,0 +1,13 @@ +{ + "id": "mattermost-gyazo", + "name": "Gyazo", + "description": "Format messages with gyazo links.", + "version": "0.1.0", + "backend": { + "executable": "server/plugin.exe" + }, + "settings_schema": { + "footer": "No configuration necessary. For more information please see https://github.com/seansackowitz/mattermost-plugin-gyazo" + } +} + diff --git a/server/Gopkg.lock b/server/Gopkg.lock new file mode 100644 index 0000000..c40ad7f --- /dev/null +++ b/server/Gopkg.lock @@ -0,0 +1,133 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + name = "github.com/davecgh/go-spew" + packages = ["spew"] + revision = "346938d642f2ec3594ed81d874461961cd0faa76" + version = "v1.1.0" + +[[projects]] + branch = "master" + name = "github.com/gorilla/websocket" + packages = ["."] + revision = "5ed622c449da6d44c3c8329331ff47a9e5844f71" + +[[projects]] + name = "github.com/mattermost/mattermost-server" + packages = [ + "mlog", + "model", + "plugin", + "plugin/plugintest", + "plugin/plugintest/mock", + "plugin/rpcplugin", + "utils/jsonutils", + "utils/markdown" + ] + revision = "d4761a94cebfd667373e1635dd1c9ad334b3b80c" + version = "v5.0.0-rc4" + +[[projects]] + name = "github.com/nicksnyder/go-i18n" + packages = [ + "i18n", + "i18n/bundle", + "i18n/language", + "i18n/translation" + ] + revision = "0dc1626d56435e9d605a29875701721c54bc9bbd" + version = "v1.10.0" + +[[projects]] + name = "github.com/pborman/uuid" + packages = ["."] + revision = "e790cca94e6cc75c7064b1332e63811d4aae1a53" + version = "v1.1" + +[[projects]] + name = "github.com/pelletier/go-toml" + packages = ["."] + revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194" + version = "v1.2.0" + +[[projects]] + name = "github.com/pkg/errors" + packages = ["."] + revision = "645ef00459ed84a119197bfb8d8205042c6df63d" + version = "v0.8.0" + +[[projects]] + name = "github.com/pmezard/go-difflib" + packages = ["difflib"] + revision = "792786c7400a136282c1664665ae0a8db921c6c2" + version = "v1.0.0" + +[[projects]] + name = "github.com/stretchr/objx" + packages = ["."] + revision = "477a77ecc69700c7cdeb1fa9e129548e1c1c393c" + version = "v0.1.1" + +[[projects]] + name = "github.com/stretchr/testify" + packages = [ + "assert", + "mock" + ] + revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686" + version = "v1.2.2" + +[[projects]] + name = "go.uber.org/atomic" + packages = ["."] + revision = "1ea20fb1cbb1cc08cbd0d913a96dead89aa18289" + version = "v1.3.2" + +[[projects]] + name = "go.uber.org/multierr" + packages = ["."] + revision = "3c4937480c32f4c13a875a1829af76c98ca3d40a" + version = "v1.1.0" + +[[projects]] + name = "go.uber.org/zap" + packages = [ + ".", + "buffer", + "internal/bufferpool", + "internal/color", + "internal/exit", + "zapcore" + ] + revision = "eeedf312bc6c57391d84767a4cd413f02a917974" + source = "https://github.com/uber-go/zap" + version = "v1.8.0" + +[[projects]] + branch = "master" + name = "golang.org/x/crypto" + packages = [ + "bcrypt", + "blowfish" + ] + revision = "37a17fe027db43f76fd88b056ddf588563fc8722" + +[[projects]] + name = "gopkg.in/natefinch/lumberjack.v2" + packages = ["."] + revision = "a96e63847dc3c67d17befa69c303767e2f84e54f" + version = "v2.1" + +[[projects]] + name = "gopkg.in/yaml.v2" + packages = ["."] + revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" + version = "v2.2.1" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "77eae7c50d9a6bde623e5a55e53c31a9027d67644ac376fbe995d22c9b806ef1" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/server/Gopkg.toml b/server/Gopkg.toml new file mode 100644 index 0000000..8c08553 --- /dev/null +++ b/server/Gopkg.toml @@ -0,0 +1,11 @@ + +[[constraint]] + name = "github.com/mattermost/mattermost-server" + branch = "release-5.0" + #version = "5.0.0" should be switched to version after 5.0 ships vs master +[[override]] + name = "go.uber.org/zap" + source = "https://github.com/uber-go/zap" +[prune] + go-tests = true + unused-packages = true diff --git a/server/config.go b/server/config.go new file mode 100644 index 0000000..29653d9 --- /dev/null +++ b/server/config.go @@ -0,0 +1,5 @@ +package main + +// Configuration from config.json +type Configuration struct { +} diff --git a/server/main.go b/server/main.go new file mode 100644 index 0000000..9a2f5e8 --- /dev/null +++ b/server/main.go @@ -0,0 +1,21 @@ +package main + +import ( + "github.com/mattermost/mattermost-server/plugin/rpcplugin" +) + +func main() { + rpcplugin.Main(&Plugin{}) +} + +type GyazoJson struct { + Version string `json:"version"` + Type string `json:"type"` + Provider_name string `json:"provider_name"` + Provider_url string `json:"provider_url"` + Url string `json:"url"` + Html string `json:"html"` + Width int `json:"width"` + Height int `json:"height"` + Scale float32 `json:"scale"` +} diff --git a/server/plugin.go b/server/plugin.go new file mode 100644 index 0000000..6640558 --- /dev/null +++ b/server/plugin.go @@ -0,0 +1,85 @@ +package main + +import ( + "encoding/json" + "net/http" + "regexp" + "strings" + "sync/atomic" + "time" + + "github.com/mattermost/mattermost-server/mlog" + "github.com/mattermost/mattermost-server/model" + "github.com/mattermost/mattermost-server/plugin" +) + +// Plugin the main struct for everything +type Plugin struct { + api plugin.API + links atomic.Value +} + +// OnActivate is invoked when the plugin is activated. +func (p *Plugin) OnActivate(api plugin.API) error { + p.api = api + + if err := p.OnConfigurationChange(); err != nil { + return err + } + + return nil +} + +// OnConfigurationChange is invoked when configuration changes may have been made. +func (p *Plugin) OnConfigurationChange() error { + var c Configuration + err := p.api.LoadPluginConfiguration(&c) + if err != nil { + return err + } + + return nil +} + +var myClient = &http.Client{Timeout: 10 * time.Second} + +func getJson(url string, target interface{}) error { + r, err := myClient.Get("https://api.gyazo.com/api/oembed?url=" + url) + if err != nil { + return err + } + defer r.Body.Close() + + return json.NewDecoder(r.Body).Decode(target) +} + +func (p *Plugin) FilterPost(post *model.Post) (*model.Post, string) { + message := post.Message + r, _ := regexp.Compile("(https://gyazo.com/)[a-z0-9]*") + link := r.FindString(message) + if len(link) > 0 { + return p.FormatPost(post, link), "" + } + + return post, "" +} + +func (p *Plugin) FormatPost(post *model.Post, gyazo string) *model.Post { + gyazojson := new(GyazoJson) + getJson(gyazo, gyazojson) + url := gyazojson.Url + if gyazojson.Type == "video" { + url = strings.Replace(gyazo, "https://", "https://i.", -1) + ".gif" + } + post.Message = "[Gyazo](" + gyazo + ")\n" + url + + mlog.Error(post.Message) + return post +} + +// MessageWillBePosted is invoked when a message is posted by a user before it is commited +// to the database. +func (p *Plugin) MessageWillBePosted(post *model.Post) (*model.Post, string) { + mlog.Error(post.Message) + return p.FilterPost(post) +}