Verified Commit f3a3e622 authored by j's avatar j
Browse files

Update deps, add build Dockerfile

parent 5cbfc374
FROM golang:stretch
COPY . /app
WORKDIR /app
RUN make dist
\ No newline at end of file
......@@ -2,6 +2,9 @@ GO ?= $(shell command -v go 2> /dev/null)
NPM ?= $(shell command -v npm 2> /dev/null)
CURL ?= $(shell command -v curl 2> /dev/null)
MANIFEST_FILE ?= plugin.json
GOPATH ?= $(shell go env GOPATH)
GO_TEST_FLAGS ?= -race
GO_BUILD_FLAGS ?=
MM_UTILITIES_DIR ?= ../mattermost-utilities
export GO111MODULE=on
......@@ -14,6 +17,11 @@ include build/setup.mk
BUNDLE_NAME ?= $(PLUGIN_ID)-$(PLUGIN_VERSION).tar.gz
# Include custom makefile, if present
ifneq ($(wildcard build/custom.mk),)
include build/custom.mk
endif
## Checks the code style, tests, builds and bundles the plugin.
all: check-style test dist
......@@ -22,55 +30,34 @@ all: check-style test dist
apply:
./build/bin/manifest apply
## Runs govet and gofmt against all packages.
## Runs golangci-lint and eslint.
.PHONY: check-style
check-style: webapp/.npminstall gofmt govet
check-style: webapp/.npminstall golangci-lint
@echo Checking for style guide compliance
ifneq ($(HAS_WEBAPP),)
cd webapp && npm run lint
endif
## Runs gofmt against all packages.
.PHONY: gofmt
gofmt:
ifneq ($(HAS_SERVER),)
@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
endif
## Runs govet against all packages.
.PHONY: govet
govet:
ifneq ($(HAS_SERVER),)
@echo Running govet
@# Workaroung because you can't install binaries without adding them to go.mod
env GO111MODULE=off $(GO) get golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow
$(GO) vet ./server/...
$(GO) vet -vettool=$(GOPATH)/bin/shadow ./server/...
@echo Govet success
endif
## Run golangci-lint on codebase.
.PHONY: golangci-lint
golangci-lint:
@if ! [ -x "$$(command -v golangci-lint)" ]; then \
echo "golangci-lint is not installed. Please see https://github.com/golangci/golangci-lint#install for installation instructions."; \
exit 1; \
fi; \
@echo Running golangci-lint
golangci-lint run ./...
## Builds the server, if it exists, including support for multiple architectures.
.PHONY: server
server:
ifneq ($(HAS_SERVER),)
mkdir -p server/dist;
cd server && env GOOS=linux GOARCH=amd64 $(GO) build -o dist/plugin-linux-amd64;
cd server && env GOOS=darwin GOARCH=amd64 $(GO) build -o dist/plugin-darwin-amd64;
cd server && env GOOS=windows GOARCH=amd64 $(GO) build -o dist/plugin-windows-amd64.exe;
cd server && env GOOS=linux GOARCH=amd64 $(GO) build $(GO_BUILD_FLAGS) -o dist/plugin-linux-amd64;
cd server && env GOOS=darwin GOARCH=amd64 $(GO) build $(GO_BUILD_FLAGS) -o dist/plugin-darwin-amd64;
cd server && env GOOS=windows GOARCH=amd64 $(GO) build $(GO_BUILD_FLAGS) -o dist/plugin-windows-amd64.exe;
endif
## Ensures NPM dependencies are installed without having to run this all the time.
......@@ -87,6 +74,14 @@ ifneq ($(HAS_WEBAPP),)
cd webapp && $(NPM) run build;
endif
## Builds the webapp in debug mode, if it exists.
.PHONY: webapp-debug
webapp-debug: webapp/.npminstall
ifneq ($(HAS_WEBAPP),)
cd webapp && \
$(NPM) run debug;
endif
## Generates a tar bundle of the plugin for install.
.PHONY: bundle
bundle:
......@@ -116,48 +111,45 @@ endif
dist: apply server webapp bundle
## Installs the plugin to a (development) server.
## It uses the API if appropriate environment variables are defined,
## and otherwise falls back to trying to copy the plugin to a sibling mattermost-server directory.
.PHONY: deploy
deploy: dist
## It uses the API if appropriate environment variables are defined,
## or copying the files directly to a sibling mattermost-server directory.
ifneq ($(and $(MM_SERVICESETTINGS_SITEURL),$(MM_ADMIN_USERNAME),$(MM_ADMIN_PASSWORD),$(CURL)),)
@echo "Installing plugin via API"
$(eval TOKEN := $(shell curl -i -X POST $(MM_SERVICESETTINGS_SITEURL)/api/v4/users/login -d '{"login_id": "$(MM_ADMIN_USERNAME)", "password": "$(MM_ADMIN_PASSWORD)"}' | grep Token | cut -f2 -d' ' 2> /dev/null))
@curl -s -H "Authorization: Bearer $(TOKEN)" -X POST $(MM_SERVICESETTINGS_SITEURL)/api/v4/plugins -F "plugin=@dist/$(BUNDLE_NAME)" -F "force=true" > /dev/null && \
curl -s -H "Authorization: Bearer $(TOKEN)" -X POST $(MM_SERVICESETTINGS_SITEURL)/api/v4/plugins/$(PLUGIN_ID)/enable > /dev/null && \
echo "OK." || echo "Sorry, something went wrong."
else ifneq ($(wildcard ../mattermost-server/.*),)
@echo "Installing plugin via filesystem. Server restart and manual plugin enabling required"
mkdir -p ../mattermost-server/plugins
tar -C ../mattermost-server/plugins -zxvf dist/$(BUNDLE_NAME)
else
@echo "No supported deployment method available. Install plugin manually."
endif
./build/bin/deploy $(PLUGIN_ID) dist/$(BUNDLE_NAME)
.PHONY: debug-deploy
debug-deploy: debug-dist deploy
.PHONY: debug-dist
debug-dist: apply server webapp-debug bundle
## Runs any lints and unit tests defined for the server and webapp, if they exist.
.PHONY: test
test: webapp/.npminstall
ifneq ($(HAS_SERVER),)
$(GO) test -race -v ./server/...
$(GO) test -v $(GO_TEST_FLAGS) ./server/...
endif
ifneq ($(HAS_WEBAPP),)
cd webapp && $(NPM) run fix;
cd webapp && $(NPM) run fix && $(NPM) run test;
endif
## Creates a coverage report for the server code.
.PHONY: coverage
coverage: server/.depensure webapp/.npminstall
coverage: webapp/.npminstall
ifneq ($(HAS_SERVER),)
$(GO) test -race -coverprofile=server/coverage.txt ./server/...
$(GO) test $(GO_TEST_FLAGS) -coverprofile=server/coverage.txt ./server/...
$(GO) tool cover -html=server/coverage.txt
endif
## Extract strings for translation from the source code.
.PHONY: i18n-extract
i18n-extract:
i18n-extract:
ifneq ($(HAS_WEBAPP),)
@[[ -d $(MM_UTILITIES_DIR) ]] || echo "You must clone github.com/mattermost/mattermost-utilities repo in .. to use this command"
@[[ -d $(MM_UTILITIES_DIR) ]] && cd $(MM_UTILITIES_DIR) && npm install && npm run babel && node mmjstool/build/index.js i18n extract-webapp --webapp-dir ../mattermost-plugin-demo/webapp
ifeq ($(HAS_MM_UTILITIES),)
@echo "You must clone github.com/mattermost/mattermost-utilities repo in .. to use this command"
else
cd $(MM_UTILITIES_DIR) && npm install && npm run babel && node mmjstool/build/index.js i18n extract-webapp --webapp-dir $(PWD)/webapp
endif
endif
## Clean removes all build artifacts.
......@@ -165,15 +157,17 @@ endif
clean:
rm -fr dist/
ifneq ($(HAS_SERVER),)
rm -fr server/coverage.txt
rm -fr server/dist
endif
ifneq ($(HAS_WEBAPP),)
rm -fr webapp/.npminstall
rm -fr webapp/junit.xml
rm -fr webapp/dist
rm -fr webapp/node_modules
endif
rm -fr build/bin/
# Help documentatin à la https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html
# Help documentation à la https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html
help:
@cat Makefile | grep -v '\.PHONY' | grep -v '\help:' | grep -B1 -E '^[a-zA-Z0-9_.-]+:.*' | sed -e "s/:.*//" | sed -e "s/^## //" | grep -v '\-\-' | sed '1!G;h;$$!d' | awk 'NR%2{printf "\033[36m%-30s\033[0m",$$0;next;}1' | sort
module github.com/ZeusWPI/mattermost-great-filter/server
module github.com/ZeusWPI/mattermost-great-filter
go 1.12
go 1.14
require (
github.com/BurntSushi/toml v0.3.1 // indirect
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect
github.com/golang/protobuf v1.1.0 // indirect
github.com/gorilla/websocket v0.0.0-20180605202552-5ed622c449da // indirect
github.com/hashicorp/go-hclog v0.0.0-20180402200405-69ff559dc25f // indirect
github.com/hashicorp/go-plugin v0.0.0-20180331002553-e8d22c780116 // indirect
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect
github.com/mattermost/mattermost-server v5.4.0+incompatible
github.com/mattermost/viper v1.0.4 // indirect
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 // indirect
github.com/nicksnyder/go-i18n v1.10.0 // indirect
github.com/oklog/run v1.0.0 // indirect
github.com/pborman/uuid v0.0.0-20170612153648-e790cca94e6c // indirect
github.com/pkg/errors v0.8.0
go.uber.org/atomic v1.3.2 // indirect
go.uber.org/multierr v1.1.0 // indirect
go.uber.org/zap v1.8.0 // indirect
golang.org/x/net v0.0.0-20180706051357-32a936f46389 // indirect
golang.org/x/sync v0.0.0-20190423024810-112230192c58 // indirect
google.golang.org/genproto v0.0.0-20180627194029-ff3583edef7d // indirect
google.golang.org/grpc v1.13.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0-20170531160350-a96e63847dc3 // indirect
github.com/go-ldap/ldap v3.0.3+incompatible // indirect
github.com/mattermost/mattermost-plugin-api v0.0.12-0.20200925172129-8ea2e7c0b42b
github.com/mattermost/mattermost-server v5.11.1+incompatible
github.com/mattermost/mattermost-server/v5 v5.28.0
github.com/nicksnyder/go-i18n v1.10.1 // indirect
github.com/pkg/errors v0.9.1
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
)
// Workaround for https://github.com/golang/go/issues/30831 and fallout.
replace github.com/golang/lint => github.com/golang/lint v0.0.0-20190227174305-8f45f776aaf1
This diff is collapsed.
......@@ -2,7 +2,7 @@
"id": "mattermost-great-filter",
"name": "The Great Filter",
"description": "For filtering out messages",
"version": "0.1.5",
"version": "0.1.6",
"server": {
"executables": {
"linux-amd64": "server/dist/plugin-linux-amd64",
......
......@@ -5,5 +5,5 @@ var manifest = struct {
Version string
}{
Id: "mattermost-great-filter",
Version: "0.1.5",
Version: "0.1.6",
}
......@@ -5,17 +5,86 @@ import (
"net/http"
"strings"
"regexp"
"sync"
"reflect"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/plugin"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/plugin"
"github.com/pkg/errors"
)
type configuration struct {
Channel string
AllowedUsers string
ChannelNoUpdate string
}
// Clone shallow copies the configuration. Your implementation may require a deep copy if
// your configuration has reference types.
func (c *configuration) Clone() *configuration {
var clone = *c
return &clone
}
// 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()
if p.configuration == nil {
return &configuration{}
}
return p.configuration
}
// setConfiguration replaces the active configuration under lock.
//
// Do not call setConfiguration while holding the configurationLock, as sync.Mutex is not
// reentrant. In particular, avoid using the plugin API entirely, as this may in turn trigger a
// hook back into the plugin. If that hook attempts to acquire this lock, a deadlock may occur.
//
// 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()
if configuration != nil && p.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.
if reflect.ValueOf(*configuration).NumField() == 0 {
return
}
panic("setConfiguration called with the existing configuration")
}
p.configuration = configuration
}
// OnConfigurationChange is invoked when configuration changes may have been made.
func (p *Plugin) OnConfigurationChange() error {
var configuration = new(configuration)
// Load the public configuration fields from the Mattermost server configuration.
if err := p.API.LoadPluginConfiguration(configuration); err != nil {
return errors.Wrap(err, "failed to load plugin configuration")
}
p.setConfiguration(configuration)
return nil
}
type Plugin struct {
plugin.MattermostPlugin
Channel string
AllowedUsers string
ChannelNoUpdate string
configurationLock sync.RWMutex
configuration *configuration
}
func main() {
......@@ -34,6 +103,7 @@ func (p *Plugin) ServeHTTP(c *plugin.Context, w http.ResponseWriter, r *http.Req
}
func (p *Plugin) FilterPost(post *model.Post) (*model.Post, string) {
configuration := p.getConfiguration()
// Check if channel is the forbidden channel
channel, err := p.API.GetChannel(post.ChannelId)
if err != nil {
......@@ -41,7 +111,7 @@ func (p *Plugin) FilterPost(post *model.Post) (*model.Post, string) {
return nil, ""
}
if strings.Contains(post.Message, "updated the channel header") {
noUpdateChannels := strings.Split(p.ChannelNoUpdate, " ")
noUpdateChannels := strings.Split(configuration.ChannelNoUpdate, " ")
for _, noUpdateChannel := range noUpdateChannels {
if noUpdateChannel == channel.Name {
return nil, "You are not allowed to post message updates in this channel"
......@@ -74,20 +144,37 @@ func (p *Plugin) FilterPost(post *model.Post) (*model.Post, string) {
post.Message = ssm
return post, ""
}
if channel.Name != p.Channel {
return post, ""
}
// Check if the user is allowed
user, err := p.API.GetUser(post.UserId)
if err != nil {
p.API.LogError("Failed to find user in post")
return nil, ""
}
allowedUsers := strings.Split(configuration.AllowedUsers, " ")
if channel.Name == "bestuur-intern" {
for _, allowedUser := range allowedUsers {
if allowedUser == user.Username {
return nil, ""
}
}
if strings.HasPrefix(post.Message, "!") {
return nil, ""
}
p.API.SendEphemeralPost(post.UserId, &model.Post{
ChannelId: post.ChannelId,
Message: "This is the internal channel of the board, so only the board can post in it. If you think it's appropriate, override by starting your message with '!'",
Props: map[string]interface{}{
"sent_by_plugin": true,
},
})
return nil, "This is the internal channel of the board, so only the board can post in it. If you think it's appropriate, override by starting your message with '!'"
}
if channel.Name != configuration.Channel {
return post, ""
}
allowedUsers := strings.Split(p.AllowedUsers, " ")
for _, allowedUser := range allowedUsers {
if allowedUser == user.Username {
return nil, ""
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment