Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
dist
vendor/
bin/
podman/**
!podman/env.example
.env
88 changes: 44 additions & 44 deletions CONTRIBUTING.md
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ This document is a primer for developing in this repository.
```

4. **Mattermost Server** (9.3.0+)
- Either local installation or Docker container
- Either local installation or Podman container
- Admin access for plugin management

5. **Git**
Expand All @@ -58,7 +58,7 @@ This document is a primer for developing in this repository.
```

This installs:
- `golangci-lint v2.5.0` - Go code linter
- `golangci-lint v2.6.0` - Go code linter
- `gotestsum v1.13.0` - Enhanced test runner

3. **Configure plugin deployment (optional - for local testing):**
Expand Down Expand Up @@ -111,60 +111,60 @@ The project uses GNU Make for build automation. Here are all available commands:

### Primary Build Commands

| Command | Description | Usage |
|---------|-------------|-------|
| `make all` | Complete build pipeline: check-style → test → dist | Use before committing |
| `make dist` | Build production plugin bundle | Creates `dist/mattermost-community-toolkit-*.tar.gz` |
| `make server` | Build server binaries only | Builds for linux-amd64 and linux-arm64 |
| `make webapp` | Build webapp (currently disabled) | N/A - webapp is WIP |
| `make bundle` | Create distribution tarball | Packages built artifacts |
| `make clean` | Remove all build artifacts | Clean slate rebuild |
| Command | Description | Usage |
| ------------- | -------------------------------------------------- | ---------------------------------------------------- |
| `make all` | Complete build pipeline: check-style → test → dist | Use before committing |
| `make dist` | Build production plugin bundle | Creates `dist/mattermost-community-toolkit-*.tar.gz` |
| `make server` | Build server binaries only | Builds for linux-amd64 and linux-arm64 |
| `make webapp` | Build webapp (currently disabled) | N/A - webapp is WIP |
| `make bundle` | Create distribution tarball | Packages built artifacts |
| `make clean` | Remove all build artifacts | Clean slate rebuild |

### Development Commands

| Command | Description | Usage |
|---------|-------------|-------|
| `make apply` | Propagate manifest changes | Run after editing `plugin.json` |
| `make deploy` | Build and install to server | Requires configured `pluginctl` |
| `make watch` | Auto-rebuild on file changes | For webapp development |
| `make deploy-from-watch` | Deploy watched changes | Use with `make watch` |
| Command | Description | Usage |
| ------------------------ | ---------------------------- | ------------------------------- |
| `make apply` | Propagate manifest changes | Run after editing `plugin.json` |
| `make deploy` | Build and install to server | Requires configured `pluginctl` |
| `make watch` | Auto-rebuild on file changes | For webapp development |
| `make deploy-from-watch` | Deploy watched changes | Use with `make watch` |

### Testing Commands

| Command | Description | Usage |
|---------|-------------|-------|
| `make test` | Run all tests with race detection | Standard test run |
| `make test-ci` | CI-optimized test with JUnit output | For CI pipelines |
| `make coverage` | Generate test coverage report | Opens HTML report in browser |
| `make check-style` | Run linters (Go + JS) | Must pass before commit |
| Command | Description | Usage |
| ------------------ | ----------------------------------- | ---------------------------- |
| `make test` | Run all tests with race detection | Standard test run |
| `make test-ci` | CI-optimized test with JUnit output | For CI pipelines |
| `make coverage` | Generate test coverage report | Opens HTML report in browser |
| `make check-style` | Run linters (Go + JS) | Must pass before commit |

### Plugin Management Commands

| Command | Description | Usage |
|---------|-------------|-------|
| `make enable` | Enable the plugin | After deployment |
| `make disable` | Disable the plugin | For testing |
| `make reset` | Restart plugin (disable + enable) | Quick restart |
| `make kill` | Force kill plugin process | Emergency stop |
| `make logs` | View plugin logs | Debugging |
| `make logs-watch` | Tail plugin logs | Real-time monitoring |
| Command | Description | Usage |
| ----------------- | --------------------------------- | -------------------- |
| `make enable` | Enable the plugin | After deployment |
| `make disable` | Disable the plugin | For testing |
| `make reset` | Restart plugin (disable + enable) | Quick restart |
| `make kill` | Force kill plugin process | Emergency stop |
| `make logs` | View plugin logs | Debugging |
| `make logs-watch` | Tail plugin logs | Real-time monitoring |

### Debugging Commands

| Command | Description | Usage |
|---------|-------------|-------|
| `make attach` | Attach dlv debugger | Interactive debugging |
| `make attach-headless` | Headless dlv on port 2346 | Remote debugging |
| `make detach` | Detach debugger | Stop debugging |
| `make setup-attach` | Find plugin PID | Internal use |
| Command | Description | Usage |
| ---------------------- | ------------------------- | --------------------- |
| `make attach` | Attach dlv debugger | Interactive debugging |
| `make attach-headless` | Headless dlv on port 2346 | Remote debugging |
| `make detach` | Detach debugger | Stop debugging |
| `make setup-attach` | Find plugin PID | Internal use |

### Utility Commands

| Command | Description | Usage |
|---------|-------------|-------|
| `make install-go-tools` | Install required Go tools | First-time setup |
| `make i18n-extract` | Extract translatable strings | For localization |
| `make help` | Show all available commands | Quick reference |
| Command | Description | Usage |
| ----------------------- | ---------------------------- | ---------------- |
| `make install-go-tools` | Install required Go tools | First-time setup |
| `make i18n-extract` | Extract translatable strings | For localization |
| `make help` | Show all available commands | Quick reference |

### Environment Variables

Expand Down Expand Up @@ -268,7 +268,7 @@ goimports -w -local github.com/rocky-linux/mattermost-plugin-community-toolkit s

### Linting Rules

We use `golangci-lint v2.5.0+` with linting rules available in the file `.golangci.yml`
We use `golangci-lint v2.6.0+` with linting rules configured in `.golangci.yml`

## Debugging

Expand Down Expand Up @@ -308,7 +308,7 @@ We use `golangci-lint v2.5.0+` with linting rules available in the file `.golang

## Additional Resources

- [Plugin Architecture Overview](.local/ARCHITECTURE_OVERVIEW.md)
- [Mattermost Plugin Developer Docs](https://developers.mattermost.com/integrate/plugins/)
- [Go Documentation](https://go.dev/doc/)
- [Original Repository](https://github.com/mattermost/mattermost-plugin-profanity-filter)
- [Podman Development Environment](docs/PODMAN_DEVELOPMENT.md)
- [New User Moderation Features](docs/NEW_USER_MODERATION.md)
150 changes: 149 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ apply:
## Install go tools
install-go-tools:
@echo Installing go tools
$(GO) install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.5.0
$(GO) install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.6.0
$(GO) install gotest.tools/[email protected]

## Runs eslint and golangci-lint
Expand Down Expand Up @@ -94,6 +94,10 @@ else
endif
endif

## Alias for server target - builds the server component.
.PHONY: build
build: server

## Ensures NPM dependencies are installed without having to run this all the time.
webapp/node_modules: $(wildcard webapp/package.json)
ifneq ($(HAS_WEBAPP),)
Expand Down Expand Up @@ -279,6 +283,24 @@ ifneq ($(HAS_WEBAPP),)
endif
rm -fr build/bin/

## Formats Go and Markdown code.
.PHONY: format
format:
@echo Formatting code...
ifneq ($(HAS_SERVER),)
@echo Formatting Go files...
$(GO) fmt ./...
endif
@echo Formatting Markdown files...
@if command -v prettier > /dev/null 2>&1; then \
prettier --write "**/*.md"; \
elif command -v npx > /dev/null 2>&1; then \
npx --yes prettier --write "**/*.md"; \
else \
echo "Warning: prettier not found. Install it with 'npm install -g prettier' to format Markdown files."; \
fi
@echo Formatting complete.

.PHONY: logs
logs:
./build/bin/pluginctl logs $(PLUGIN_ID)
Expand All @@ -287,6 +309,132 @@ logs:
logs-watch:
./build/bin/pluginctl logs-watch $(PLUGIN_ID)

# Development environment management with Podman Compose
PODMAN_COMPOSE_FILE ?= podman-compose.yml
PODMAN_COMPOSE := podman-compose -f $(PODMAN_COMPOSE_FILE)

## Sets up the required directories for Podman development stack.
.PHONY: dev-setup
dev-setup:
@echo "Setting up development environment directories..."
@mkdir -p podman/data/mattermost/plugins podman/data/mattermost/client/plugins podman/data/postgres podman/config
@chmod -R 777 podman/config podman/data/mattermost 2>/dev/null || true
@echo "Directories created and permissions set."

## Starts the Podman Compose development stack.
.PHONY: dev-up
dev-up: dev-setup
@echo "Starting development environment..."
$(PODMAN_COMPOSE) up -d
@echo "Waiting for Mattermost to be ready..."
@timeout 60 bash -c 'until $$(curl -s http://localhost:8065/api/v4/system/ping > /dev/null 2>&1); do sleep 2; done' || echo "Mattermost is starting. Access at http://localhost:8065"
@echo "Creating admin account if it doesn't exist..."
@$(MAKE) dev-create-admin || echo "Admin account already exists or creation failed"

## Stops the Podman Compose development stack.
.PHONY: dev-down
dev-down:
@echo "Stopping development environment..."
$(PODMAN_COMPOSE) down

## Creates the admin account if it doesn't exist.
## Uses credentials from podman-compose.yml (admin/admin123/[email protected])
## Also creates a default team and adds the admin user to it.
.PHONY: dev-create-admin
dev-create-admin:
@./scripts/dev-create-admin.sh

## Alias for dev-up
.PHONY: dev-start
dev-start: dev-up

## Alias for dev-down
.PHONY: dev-stop
dev-stop: dev-down

## Restarts the Podman Compose development stack.
.PHONY: dev-restart
dev-restart: dev-down dev-up

## Removes containers, volumes, and data for a clean start.
.PHONY: dev-clean
dev-clean:
@echo "Cleaning development environment (removing containers, volumes, and data)..."
$(PODMAN_COMPOSE) down -v
sudo rm -rf podman/data/* podman/config/*
@echo "Development environment cleaned. Run 'make dev-up' to start fresh."

## Views Mattermost server logs.
.PHONY: dev-logs
dev-logs:
$(PODMAN_COMPOSE) logs mattermost

## Tails Mattermost server logs in real-time.
.PHONY: dev-logs-watch
dev-logs-watch:
$(PODMAN_COMPOSE) logs -f mattermost

## Builds and deploys the plugin to the Podman development stack.
.PHONY: dev-deploy
dev-deploy: dist
@PLUGIN_ID=$(PLUGIN_ID) BUNDLE_NAME=dist/$(BUNDLE_NAME) ./scripts/dev-deploy.sh

## Opens a shell in the Mattermost container.
.PHONY: dev-shell
dev-shell:
$(PODMAN_COMPOSE) exec mattermost /bin/sh

## Shows status of Podman Compose services.
.PHONY: dev-status
dev-status:
$(PODMAN_COMPOSE) ps

## Enables the plugin in the development environment.
.PHONY: dev-enable
dev-enable:
@./scripts/dev-check-container.sh
@MM_SERVICESETTINGS_SITEURL=http://localhost:8065 \
./build/bin/pluginctl enable $(PLUGIN_ID)

## Disables the plugin in the development environment.
.PHONY: dev-disable
dev-disable:
@./scripts/dev-check-container.sh
@MM_SERVICESETTINGS_SITEURL=http://localhost:8065 \
./build/bin/pluginctl disable $(PLUGIN_ID)

## Resets the plugin in the development environment (disables and re-enables).
.PHONY: dev-reset
dev-reset:
@./scripts/dev-check-container.sh
@MM_SERVICESETTINGS_SITEURL=http://localhost:8065 \
./build/bin/pluginctl reset $(PLUGIN_ID)

## Views plugin logs in the development environment.
.PHONY: dev-plugin-logs
dev-plugin-logs:
@./scripts/dev-check-container.sh
@MM_SERVICESETTINGS_SITEURL=http://localhost:8065 \
./build/bin/pluginctl logs $(PLUGIN_ID)

## Tails plugin logs in the development environment.
.PHONY: dev-plugin-logs-watch
dev-plugin-logs-watch:
@./scripts/dev-check-container.sh
@MM_SERVICESETTINGS_SITEURL=http://localhost:8065 \
./build/bin/pluginctl logs-watch $(PLUGIN_ID)

## Pings the Mattermost healthcheck endpoint to verify server is responding.
.PHONY: dev-check-ping
dev-check-ping:
@echo "Checking Mattermost healthcheck endpoint..."
@if $(CURL) -f -s http://localhost:8065/api/v4/system/ping > /dev/null 2>&1; then \
echo "✓ Mattermost is responding (http://localhost:8065/api/v4/system/ping)"; \
else \
echo "✗ Mattermost is not responding. Is it running? (Try 'make dev-up')"; \
exit 1; \
fi

# Help documentation à la https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html
help:
@cat Makefile build/*.mk | 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
26 changes: 13 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@ This plugin allows you to manage multiple settings relating to preventing spam a

The plugin has the following features:

* Censor/filter posts on the server (including during editing) to either reject or censor unwanted words (e.g., profanity)
* Words can be replaced with a series of characters (e.g., "\*"), or rejected outright with a message to the user
* Automatically deactivate users (cancel registration) if their username matches list of unwanted names
* Automatically deactivate users (cancel registration) if their email matches list of unwanted domains/addresses
* Prevent new users from sending direct messages to other users for some time period
- Censor/filter posts on the server (including during editing) to either reject or censor unwanted words (e.g., profanity)
- Words can be replaced with a series of characters (e.g., "\*"), or rejected outright with a message to the user
- Automatically deactivate users (cancel registration) if their username matches list of unwanted names
- Automatically deactivate users (cancel registration) if their email matches list of unwanted domains/addresses
- Prevent new users from sending direct messages to other users for some time period

In the future, this plugin will:

* Send notifications to a centralized channel of moderation actions taken
* Allow moderators to restore accounts, perform inquiries on users, see the history of the account and its changes
* Grant "trust" levels to users based on the account status and optional moderator input
* e.g., allow accounts in a certain LDAP group to bypass checks
* Be a hub for all community operations activities--moderation and otherwise
- Send notifications to a centralized channel of moderation actions taken
- Allow moderators to restore accounts, perform inquiries on users, see the history of the account and its changes
- Grant "trust" levels to users based on the account status and optional moderator input
- e.g., allow accounts in a certain LDAP group to bypass checks
- Be a hub for all community operations activities--moderation and otherwise

**Supported Mattermost Server Versions: 9.3+**

Expand All @@ -45,6 +45,6 @@ In addition to the Bad Word List, a Bad Domain and Bad Username list is availabl

Want to help improve the Mattermost Community Toolkit Plugin? Please see our [Contributing Guide](CONTRIBUTING.md) for detailed information on:

* Development environment setup
* Build system and make commands
* Debugging and troubleshooting
- Development environment setup
- Build system and make commands
- Debugging and troubleshooting
8 changes: 7 additions & 1 deletion build/manifest/main.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
// Package main provides a build tool for managing Mattermost plugin manifests.
// It handles manifest discovery, version generation, and code generation for
// server and webapp components.
package main

import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"

"github.com/mattermost/mattermost/server/public/model"
Expand Down Expand Up @@ -96,11 +100,13 @@ func findManifest() (*model.Manifest, error) {
if err != nil {
return nil, errors.Wrap(err, "failed to find manifest in current working directory")
}
// Sanitize the file path to prevent path traversal attacks
manifestFilePath = filepath.Clean(manifestFilePath)
manifestFile, err := os.Open(manifestFilePath)
if err != nil {
return nil, errors.Wrapf(err, "failed to open %s", manifestFilePath)
}
defer manifestFile.Close()
defer func() { _ = manifestFile.Close() }()

// Re-decode the manifest, disallowing unknown fields. When we write the manifest back out,
// we don't want to accidentally clobber anything we won't preserve.
Expand Down
2 changes: 1 addition & 1 deletion build/pluginctl/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ func checkJSONLogsSetting(ctx context.Context, client *model.Client4) error {
return fmt.Errorf("failed to fetch config: %w", err)
}
if cfg.LogSettings.FileJson == nil || !*cfg.LogSettings.FileJson {
return errors.New("JSON output for file logs are disabled. Please enable LogSettings.FileJson via the configration in Mattermost.") //nolint:revive,stylecheck
return errors.New("JSON output for file logs are disabled. Please enable LogSettings.FileJson via the configuration in Mattermost") //nolint:revive,stylecheck
}

return nil
Expand Down
Loading