[MM-53968] Includes mattermost-plugin-api into the mono repo (#24235)

Include https://github.com/mattermost/mattermost-plugin-api into the mono repo

Co-authored-by: Jesse Hallam <jesse.hallam@gmail.com>
Co-authored-by: Michael Kochell <mjkochell@gmail.com>
Co-authored-by: Alejandro García Montoro <alejandro.garciamontoro@gmail.com>
Co-authored-by: Ben Schumacher <ben.schumacher@mattermost.com>
Co-authored-by: Alex Dovenmuehle <alex.dovenmuehle@mattermost.com>
Co-authored-by: Michael Kochell <6913320+mickmister@users.noreply.github.com>
Co-authored-by: Christopher Poile <cpoile@gmail.com>
Co-authored-by: İlker Göktuğ Öztürk <ilkergoktugozturk@gmail.com>
Co-authored-by: Shota Gvinepadze <wineson@gmail.com>
Co-authored-by: Ali Farooq <ali.farooq0@pm.me>
Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>
Co-authored-by: Daniel Espino García <larkox@gmail.com>
Co-authored-by: Christopher Speller <crspeller@gmail.com>
Co-authored-by: Alex Dovenmuehle <adovenmuehle@gmail.com>
Co-authored-by: Szymon Gibała <szymongib@gmail.com>
Co-authored-by: Lev <1187448+levb@users.noreply.github.com>
Co-authored-by: Jason Frerich <jason.frerich@mattermost.com>
Co-authored-by: Agniva De Sarker <agnivade@yahoo.co.in>
Co-authored-by: Artur M. Wolff <artur.m.wolff@gmail.com>
Co-authored-by: Madhav Hugar <16546715+madhavhugar@users.noreply.github.com>
Co-authored-by: Joe <security.joe@pm.me>
Co-authored-by: Ibrahim Serdar Acikgoz <serdaracikgoz86@gmail.com>
Co-authored-by: José Peso <trilopin@users.noreply.github.com>
Этот коммит содержится в:
Ben Schumacher
2023-08-21 09:50:30 +02:00
коммит произвёл GitHub
родитель bc11b29807
Коммит 3ee5432664
117 изменённых файлов: 14912 добавлений и 5 удалений

Просмотреть файл

@@ -0,0 +1,53 @@
// Copyright (c) 2019-present Mattermost, Inc. All Rights Reserved.
// See License for license information.
package bot
import (
"github.com/pkg/errors"
"github.com/mattermost/mattermost/server/public/model"
"github.com/mattermost/mattermost/server/public/pluginapi"
)
type Bot interface {
Ensure(stored *model.Bot, iconPath string) error
MattermostUserID() string
String() string
}
type bot struct {
botService pluginapi.BotService
mattermostUserID string
displayName string
}
func New(botService pluginapi.BotService) Bot {
newBot := &bot{
botService: botService,
}
return newBot
}
func (bot *bot) Ensure(stored *model.Bot, iconPath string) error {
if bot.mattermostUserID != "" {
// Already done
return nil
}
botUserID, err := bot.botService.EnsureBot(stored, pluginapi.ProfileImagePath(iconPath))
if err != nil {
return errors.Wrap(err, "failed to ensure bot account")
}
bot.mattermostUserID = botUserID
bot.displayName = stored.DisplayName
return nil
}
func (bot *bot) MattermostUserID() string {
return bot.mattermostUserID
}
func (bot *bot) String() string {
return bot.displayName
}

Просмотреть файл

@@ -0,0 +1,97 @@
package admincclogger
import (
"fmt"
"github.com/mattermost/mattermost/server/public/pluginapi/experimental/bot/logger"
"github.com/mattermost/mattermost/server/public/pluginapi/experimental/bot/poster"
"github.com/mattermost/mattermost/server/public/pluginapi/experimental/common"
)
type adminCCLogger struct {
logger.Logger
dmer poster.DMer
logLevel logger.LogLevel
includeContext bool
userIDs []string
}
/*
New promotes the provided logger into a admin cc logger, sending direct messages to all the admin
ids provided through the dmer provided, about all events below the logLevel. If logVerbose is set,
it will also send the context.
- l Logger: A logger to promote.
- dmer DMer: A DMer to send the messages to the admins.
- logLevel: The highest type of message to be stored in telemetry.
- includeContext: Whether the log context should be messaged to the admins.
- userIDs: The user IDs of the admins.
*/
func New(l logger.Logger, dmer poster.DMer, logLevel logger.LogLevel, includeContext bool, userIDs ...string) logger.Logger {
return &adminCCLogger{
Logger: l,
dmer: dmer,
logLevel: logLevel,
includeContext: includeContext,
userIDs: userIDs,
}
}
// NewFromAPI creates a adminCCLogger directly from a LogAPI instead of passing a logger.
func NewFromAPI(api common.LogAPI, dmer poster.DMer, logLevel logger.LogLevel, includeContext bool, userIDs ...string) logger.Logger {
return New(logger.New(api), dmer, logLevel, includeContext, userIDs...)
}
func (l *adminCCLogger) Debugf(format string, args ...interface{}) {
l.Logger.Debugf(format, args...)
message := fmt.Sprintf(format, args...)
if logger.Level(l.logLevel) >= 4 {
l.logToAdmins("DEBUG", message)
}
}
func (l *adminCCLogger) Errorf(format string, args ...interface{}) {
l.Logger.Errorf(format, args...)
message := fmt.Sprintf(format, args...)
if logger.Level(l.logLevel) >= 1 {
l.logToAdmins("ERROR", message)
}
}
func (l *adminCCLogger) Infof(format string, args ...interface{}) {
l.Logger.Infof(format, args...)
message := fmt.Sprintf(format, args...)
if logger.Level(l.logLevel) >= 3 {
l.logToAdmins("INFO", message)
}
}
func (l *adminCCLogger) Warnf(format string, args ...interface{}) {
l.Logger.Warnf(format, args...)
message := fmt.Sprintf(format, args...)
if logger.Level(l.logLevel) >= 2 {
l.logToAdmins("WARN", message)
}
}
func (l *adminCCLogger) logToAdmins(level, message string) {
context := l.Context()
if l.includeContext && len(context) > 0 {
message += "\n" + common.JSONBlock(context)
}
_ = l.dmAdmins("(log " + level + ") " + message)
}
func (l *adminCCLogger) dmAdmins(format string, args ...interface{}) error {
for _, id := range l.userIDs {
_, err := l.dmer.DM(id, format, args)
if err != nil {
return err
}
}
return nil
}

Просмотреть файл

@@ -0,0 +1,82 @@
// Copyright (c) 2019-present Mattermost, Inc. All Rights Reserved.
// See License for license information.
package logger
import (
"fmt"
"time"
"github.com/mattermost/mattermost/server/public/pluginapi/experimental/common"
)
type defaultLogger struct {
logContext LogContext
logAPI common.LogAPI
}
/*
New creates a new logger.
- api: LogAPI implementation
*/
func New(api common.LogAPI) Logger {
l := &defaultLogger{
logAPI: api,
}
return l
}
func (l *defaultLogger) With(logContext LogContext) Logger {
newLogger := *l
if len(newLogger.logContext) == 0 {
newLogger.logContext = map[string]interface{}{}
}
for k, v := range logContext {
newLogger.logContext[k] = v
}
return &newLogger
}
func (l *defaultLogger) WithError(err error) Logger {
newLogger := *l
if len(newLogger.logContext) == 0 {
newLogger.logContext = map[string]interface{}{}
}
newLogger.logContext[ErrorKey] = err.Error()
return &newLogger
}
func (l *defaultLogger) Context() LogContext {
return l.logContext
}
func (l *defaultLogger) Timed() Logger {
return l.With(LogContext{
timed: time.Now(),
})
}
func (l *defaultLogger) Debugf(format string, args ...interface{}) {
measure(l.logContext)
message := fmt.Sprintf(format, args...)
l.logAPI.LogDebug(message, toKeyValuePairs(l.logContext)...)
}
func (l *defaultLogger) Errorf(format string, args ...interface{}) {
measure(l.logContext)
message := fmt.Sprintf(format, args...)
l.logAPI.LogError(message, toKeyValuePairs(l.logContext)...)
}
func (l *defaultLogger) Infof(format string, args ...interface{}) {
measure(l.logContext)
message := fmt.Sprintf(format, args...)
l.logAPI.LogInfo(message, toKeyValuePairs(l.logContext)...)
}
func (l *defaultLogger) Warnf(format string, args ...interface{}) {
measure(l.logContext)
message := fmt.Sprintf(format, args...)
l.logAPI.LogWarn(message, toKeyValuePairs(l.logContext)...)
}

Просмотреть файл

@@ -0,0 +1,78 @@
package logger
import "time"
const (
timed = "__since"
elapsed = "Elapsed"
ErrorKey = "error"
)
// LogLevel defines the level of log messages
type LogLevel string
const (
// LogLevelDebug denotes debug messages
LogLevelDebug = "debug"
// LogLevelInfo denotes info messages
LogLevelInfo = "info"
// LogLevelWarn denotes warn messages
LogLevelWarn = "warn"
// LogLevelError denotes error messages
LogLevelError = "error"
)
// LogContext defines the context for the logs.
type LogContext map[string]interface{}
// Logger defines an object able to log messages.
type Logger interface {
// With adds a logContext to the logger.
With(LogContext) Logger
// WithError adds an Error to the logger.
WithError(error) Logger
// Context returns the current context
Context() LogContext
// Timed add a timed log context.
Timed() Logger
// Debugf logs a formatted string as a debug message.
Debugf(format string, args ...interface{})
// Errorf logs a formatted string as an error message.
Errorf(format string, args ...interface{})
// Infof logs a formatted string as an info message.
Infof(format string, args ...interface{})
// Warnf logs a formatted string as an warning message.
Warnf(format string, args ...interface{})
}
func measure(lc LogContext) {
if lc[timed] == nil {
return
}
started := lc[timed].(time.Time)
lc[elapsed] = time.Since(started).String()
delete(lc, timed)
}
// Level assigns an integer to the LogLevel string
func Level(l LogLevel) int {
switch l {
case LogLevelDebug:
return 4
case LogLevelInfo:
return 3
case LogLevelWarn:
return 2
case LogLevelError:
return 1
}
return 0
}
func toKeyValuePairs(in map[string]interface{}) (out []interface{}) {
for k, v := range in {
out = append(out, k, v)
}
return out
}

Просмотреть файл

@@ -0,0 +1,17 @@
package logger
type nilLogger struct{}
// NewNilLogger returns a logger that performs no action.
func NewNilLogger() Logger {
return &nilLogger{}
}
func (l *nilLogger) With(LogContext) Logger { return l }
func (l *nilLogger) WithError(error) Logger { return l }
func (l *nilLogger) Context() LogContext { return nil }
func (l *nilLogger) Timed() Logger { return l }
func (l *nilLogger) Debugf(string, ...interface{}) {}
func (l *nilLogger) Errorf(string, ...interface{}) {}
func (l *nilLogger) Infof(string, ...interface{}) {}
func (l *nilLogger) Warnf(string, ...interface{}) {}

Просмотреть файл

@@ -0,0 +1,80 @@
package telemetrylogger
import (
"fmt"
"github.com/mattermost/mattermost/server/public/pluginapi/experimental/bot/logger"
"github.com/mattermost/mattermost/server/public/pluginapi/experimental/common"
"github.com/mattermost/mattermost/server/public/pluginapi/experimental/telemetry"
)
type telemetryLogger struct {
logger.Logger
logLevel logger.LogLevel
tracker telemetry.Tracker
}
/*
New promotes the provided logger into a telemetry logger, storing all events below the logLevel
through the tracker.
- l Logger: A logger to promote.
- logLevel: The highest type of message to be stored in telemetry.
- tracker: The telemetry tracker to store the messages.
*/
func New(l logger.Logger, logLevel logger.LogLevel, tracker telemetry.Tracker) logger.Logger {
return &telemetryLogger{
Logger: l,
logLevel: logLevel,
tracker: tracker,
}
}
// NewFromAPI creates a telemetryLogger directly from a LogAPI instead of passing a logger.
func NewFromAPI(api common.LogAPI, logLevel logger.LogLevel, tracker telemetry.Tracker) logger.Logger {
return New(logger.New(api), logLevel, tracker)
}
func (l *telemetryLogger) Debugf(format string, args ...interface{}) {
l.Logger.Debugf(format, args...)
message := fmt.Sprintf(format, args...)
if logger.Level(l.logLevel) >= 4 {
l.logToTelemetry("DEBUG", message)
}
}
func (l *telemetryLogger) Errorf(format string, args ...interface{}) {
l.Logger.Errorf(format, args...)
message := fmt.Sprintf(format, args...)
if logger.Level(l.logLevel) >= 1 {
l.logToTelemetry("ERROR", message)
}
}
func (l *telemetryLogger) Infof(format string, args ...interface{}) {
l.Logger.Infof(format, args...)
message := fmt.Sprintf(format, args...)
if logger.Level(l.logLevel) >= 3 {
l.logToTelemetry("INFO", message)
}
}
func (l *telemetryLogger) Warnf(format string, args ...interface{}) {
l.Logger.Warnf(format, args...)
message := fmt.Sprintf(format, args...)
if logger.Level(l.logLevel) >= 2 {
l.logToTelemetry("WARN", message)
}
}
func (l *telemetryLogger) logToTelemetry(level, message string) {
properties := map[string]interface{}{}
properties["message"] = message
for k, v := range l.Context() {
properties["context_"+k] = fmt.Sprintf("%v", v)
}
_ = l.tracker.TrackEvent("logger_"+level, properties)
}

Просмотреть файл

@@ -0,0 +1,61 @@
package logger
import (
"fmt"
"testing"
"time"
)
type testLogger struct {
testing.TB
logContext LogContext
}
// NewTestLogger creates a logger for testing purposes.
func NewTestLogger() Logger {
return &testLogger{}
}
func (l *testLogger) With(logContext LogContext) Logger {
newl := *l
if len(newl.logContext) == 0 {
newl.logContext = map[string]interface{}{}
}
for k, v := range logContext {
newl.logContext[k] = v
}
return &newl
}
func (l *testLogger) WithError(err error) Logger {
newl := *l
if len(newl.logContext) == 0 {
newl.logContext = map[string]interface{}{}
}
newl.logContext[ErrorKey] = err.Error()
return &newl
}
func (l *testLogger) Context() LogContext {
return l.logContext
}
func (l *testLogger) Timed() Logger {
return l.With(LogContext{
timed: time.Now(),
})
}
func (l *testLogger) logf(prefix, format string, args ...interface{}) {
out := fmt.Sprintf(prefix+": "+format, args...)
if len(l.logContext) > 0 {
measure(l.logContext)
out += fmt.Sprintf(" -- %+v", l.logContext)
}
l.TB.Logf(out)
}
func (l *testLogger) Debugf(format string, args ...interface{}) { l.logf("DEBUG", format, args...) }
func (l *testLogger) Errorf(format string, args ...interface{}) { l.logf("ERROR", format, args...) }
func (l *testLogger) Infof(format string, args ...interface{}) { l.logf("INFO", format, args...) }
func (l *testLogger) Warnf(format string, args ...interface{}) { l.logf("WARN", format, args...) }

Просмотреть файл

@@ -0,0 +1,77 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/mattermost/mattermost/server/public/pluginapi/experimental/bot (interfaces: Bot)
// Package mock_bot is a generated GoMock package.
package mock_bot
import (
reflect "reflect"
gomock "github.com/golang/mock/gomock"
model "github.com/mattermost/mattermost/server/public/model"
)
// MockBot is a mock of Bot interface.
type MockBot struct {
ctrl *gomock.Controller
recorder *MockBotMockRecorder
}
// MockBotMockRecorder is the mock recorder for MockBot.
type MockBotMockRecorder struct {
mock *MockBot
}
// NewMockBot creates a new mock instance.
func NewMockBot(ctrl *gomock.Controller) *MockBot {
mock := &MockBot{ctrl: ctrl}
mock.recorder = &MockBotMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockBot) EXPECT() *MockBotMockRecorder {
return m.recorder
}
// Ensure mocks base method.
func (m *MockBot) Ensure(arg0 *model.Bot, arg1 string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Ensure", arg0, arg1)
ret0, _ := ret[0].(error)
return ret0
}
// Ensure indicates an expected call of Ensure.
func (mr *MockBotMockRecorder) Ensure(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ensure", reflect.TypeOf((*MockBot)(nil).Ensure), arg0, arg1)
}
// MattermostUserID mocks base method.
func (m *MockBot) MattermostUserID() string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "MattermostUserID")
ret0, _ := ret[0].(string)
return ret0
}
// MattermostUserID indicates an expected call of MattermostUserID.
func (mr *MockBotMockRecorder) MattermostUserID() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MattermostUserID", reflect.TypeOf((*MockBot)(nil).MattermostUserID))
}
// String mocks base method.
func (m *MockBot) String() string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "String")
ret0, _ := ret[0].(string)
return ret0
}
// String indicates an expected call of String.
func (mr *MockBotMockRecorder) String() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "String", reflect.TypeOf((*MockBot)(nil).String))
}

Просмотреть файл

@@ -0,0 +1,159 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/mattermost/mattermost/server/public/pluginapi/experimental/bot/logger (interfaces: Logger)
// Package mock_bot is a generated GoMock package.
package mock_bot
import (
reflect "reflect"
gomock "github.com/golang/mock/gomock"
logger "github.com/mattermost/mattermost/server/public/pluginapi/experimental/bot/logger"
)
// MockLogger is a mock of Logger interface.
type MockLogger struct {
ctrl *gomock.Controller
recorder *MockLoggerMockRecorder
}
// MockLoggerMockRecorder is the mock recorder for MockLogger.
type MockLoggerMockRecorder struct {
mock *MockLogger
}
// NewMockLogger creates a new mock instance.
func NewMockLogger(ctrl *gomock.Controller) *MockLogger {
mock := &MockLogger{ctrl: ctrl}
mock.recorder = &MockLoggerMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockLogger) EXPECT() *MockLoggerMockRecorder {
return m.recorder
}
// Context mocks base method.
func (m *MockLogger) Context() logger.LogContext {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Context")
ret0, _ := ret[0].(logger.LogContext)
return ret0
}
// Context indicates an expected call of Context.
func (mr *MockLoggerMockRecorder) Context() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Context", reflect.TypeOf((*MockLogger)(nil).Context))
}
// Debugf mocks base method.
func (m *MockLogger) Debugf(arg0 string, arg1 ...interface{}) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0}
for _, a := range arg1 {
varargs = append(varargs, a)
}
m.ctrl.Call(m, "Debugf", varargs...)
}
// Debugf indicates an expected call of Debugf.
func (mr *MockLoggerMockRecorder) Debugf(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0}, arg1...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Debugf", reflect.TypeOf((*MockLogger)(nil).Debugf), varargs...)
}
// Errorf mocks base method.
func (m *MockLogger) Errorf(arg0 string, arg1 ...interface{}) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0}
for _, a := range arg1 {
varargs = append(varargs, a)
}
m.ctrl.Call(m, "Errorf", varargs...)
}
// Errorf indicates an expected call of Errorf.
func (mr *MockLoggerMockRecorder) Errorf(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0}, arg1...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Errorf", reflect.TypeOf((*MockLogger)(nil).Errorf), varargs...)
}
// Infof mocks base method.
func (m *MockLogger) Infof(arg0 string, arg1 ...interface{}) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0}
for _, a := range arg1 {
varargs = append(varargs, a)
}
m.ctrl.Call(m, "Infof", varargs...)
}
// Infof indicates an expected call of Infof.
func (mr *MockLoggerMockRecorder) Infof(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0}, arg1...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Infof", reflect.TypeOf((*MockLogger)(nil).Infof), varargs...)
}
// Timed mocks base method.
func (m *MockLogger) Timed() logger.Logger {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Timed")
ret0, _ := ret[0].(logger.Logger)
return ret0
}
// Timed indicates an expected call of Timed.
func (mr *MockLoggerMockRecorder) Timed() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Timed", reflect.TypeOf((*MockLogger)(nil).Timed))
}
// Warnf mocks base method.
func (m *MockLogger) Warnf(arg0 string, arg1 ...interface{}) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0}
for _, a := range arg1 {
varargs = append(varargs, a)
}
m.ctrl.Call(m, "Warnf", varargs...)
}
// Warnf indicates an expected call of Warnf.
func (mr *MockLoggerMockRecorder) Warnf(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0}, arg1...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Warnf", reflect.TypeOf((*MockLogger)(nil).Warnf), varargs...)
}
// With mocks base method.
func (m *MockLogger) With(arg0 logger.LogContext) logger.Logger {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "With", arg0)
ret0, _ := ret[0].(logger.Logger)
return ret0
}
// With indicates an expected call of With.
func (mr *MockLoggerMockRecorder) With(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "With", reflect.TypeOf((*MockLogger)(nil).With), arg0)
}
// WithError mocks base method.
func (m *MockLogger) WithError(arg0 error) logger.Logger {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "WithError", arg0)
ret0, _ := ret[0].(logger.Logger)
return ret0
}
// WithError indicates an expected call of WithError.
func (mr *MockLoggerMockRecorder) WithError(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WithError", reflect.TypeOf((*MockLogger)(nil).WithError), arg0)
}

Просмотреть файл

@@ -0,0 +1,151 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/mattermost/mattermost/server/public/pluginapi/experimental/bot/poster (interfaces: Poster)
// Package mock_bot is a generated GoMock package.
package mock_bot
import (
reflect "reflect"
gomock "github.com/golang/mock/gomock"
model "github.com/mattermost/mattermost/server/public/model"
)
// MockPoster is a mock of Poster interface.
type MockPoster struct {
ctrl *gomock.Controller
recorder *MockPosterMockRecorder
}
// MockPosterMockRecorder is the mock recorder for MockPoster.
type MockPosterMockRecorder struct {
mock *MockPoster
}
// NewMockPoster creates a new mock instance.
func NewMockPoster(ctrl *gomock.Controller) *MockPoster {
mock := &MockPoster{ctrl: ctrl}
mock.recorder = &MockPosterMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockPoster) EXPECT() *MockPosterMockRecorder {
return m.recorder
}
// DM mocks base method.
func (m *MockPoster) DM(arg0, arg1 string, arg2 ...interface{}) (string, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "DM", varargs...)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// DM indicates an expected call of DM.
func (mr *MockPosterMockRecorder) DM(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DM", reflect.TypeOf((*MockPoster)(nil).DM), varargs...)
}
// DMWithAttachments mocks base method.
func (m *MockPoster) DMWithAttachments(arg0 string, arg1 ...*model.SlackAttachment) (string, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0}
for _, a := range arg1 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "DMWithAttachments", varargs...)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// DMWithAttachments indicates an expected call of DMWithAttachments.
func (mr *MockPosterMockRecorder) DMWithAttachments(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0}, arg1...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DMWithAttachments", reflect.TypeOf((*MockPoster)(nil).DMWithAttachments), varargs...)
}
// DeletePost mocks base method.
func (m *MockPoster) DeletePost(arg0 string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DeletePost", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// DeletePost indicates an expected call of DeletePost.
func (mr *MockPosterMockRecorder) DeletePost(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeletePost", reflect.TypeOf((*MockPoster)(nil).DeletePost), arg0)
}
// Ephemeral mocks base method.
func (m *MockPoster) Ephemeral(arg0, arg1, arg2 string, arg3 ...interface{}) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1, arg2}
for _, a := range arg3 {
varargs = append(varargs, a)
}
m.ctrl.Call(m, "Ephemeral", varargs...)
}
// Ephemeral indicates an expected call of Ephemeral.
func (mr *MockPosterMockRecorder) Ephemeral(arg0, arg1, arg2 interface{}, arg3 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1, arg2}, arg3...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ephemeral", reflect.TypeOf((*MockPoster)(nil).Ephemeral), varargs...)
}
// UpdatePost mocks base method.
func (m *MockPoster) UpdatePost(arg0 *model.Post) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "UpdatePost", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// UpdatePost indicates an expected call of UpdatePost.
func (mr *MockPosterMockRecorder) UpdatePost(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdatePost", reflect.TypeOf((*MockPoster)(nil).UpdatePost), arg0)
}
// UpdatePostByID mocks base method.
func (m *MockPoster) UpdatePostByID(arg0, arg1 string, arg2 ...interface{}) error {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "UpdatePostByID", varargs...)
ret0, _ := ret[0].(error)
return ret0
}
// UpdatePostByID indicates an expected call of UpdatePostByID.
func (mr *MockPosterMockRecorder) UpdatePostByID(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdatePostByID", reflect.TypeOf((*MockPoster)(nil).UpdatePostByID), varargs...)
}
// UpdatePosterID mocks base method.
func (m *MockPoster) UpdatePosterID(arg0 string) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "UpdatePosterID", arg0)
}
// UpdatePosterID indicates an expected call of UpdatePosterID.
func (mr *MockPosterMockRecorder) UpdatePosterID(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdatePosterID", reflect.TypeOf((*MockPoster)(nil).UpdatePosterID), arg0)
}

Просмотреть файл

@@ -0,0 +1,76 @@
package poster
import (
"fmt"
"github.com/mattermost/mattermost/server/public/model"
)
type defaultPoster struct {
postAPI PostAPI
id string
}
// NewPoster creates a new default poster
func NewPoster(postAPI PostAPI, id string) Poster {
return &defaultPoster{
postAPI: postAPI,
id: id,
}
}
// DM posts a simple Direct Message to the specified user
func (p *defaultPoster) DM(mattermostUserID, format string, args ...interface{}) (string, error) {
post := &model.Post{
Message: fmt.Sprintf(format, args...),
}
err := p.postAPI.DM(p.id, mattermostUserID, post)
if err != nil {
return "", err
}
return post.Id, nil
}
// DMWithAttachments posts a Direct Message that contains Slack attachments.
// Often used to include post actions.
func (p *defaultPoster) DMWithAttachments(mattermostUserID string, attachments ...*model.SlackAttachment) (string, error) {
post := model.Post{}
model.ParseSlackAttachment(&post, attachments)
err := p.postAPI.DM(p.id, mattermostUserID, &post)
if err != nil {
return "", err
}
return post.Id, nil
}
// Ephemeral sends an ephemeral message to a user
func (p *defaultPoster) Ephemeral(userID, channelID, format string, args ...interface{}) {
post := &model.Post{
UserId: p.id,
ChannelId: channelID,
Message: fmt.Sprintf(format, args...),
}
p.postAPI.SendEphemeralPost(userID, post)
}
func (p *defaultPoster) UpdatePostByID(postID, format string, args ...interface{}) error {
post, err := p.postAPI.GetPost(postID)
if err != nil {
return err
}
post.Message = fmt.Sprintf(format, args...)
return p.UpdatePost(post)
}
func (p *defaultPoster) DeletePost(postID string) error {
return p.postAPI.DeletePost(postID)
}
func (p *defaultPoster) UpdatePost(post *model.Post) error {
return p.postAPI.UpdatePost(post)
}
func (p *defaultPoster) UpdatePosterID(id string) {
p.id = id
}

Просмотреть файл

@@ -0,0 +1,414 @@
package poster
import (
"errors"
"testing"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
"github.com/mattermost/mattermost/server/public/model"
"github.com/mattermost/mattermost/server/public/plugin/plugintest"
"github.com/mattermost/mattermost/server/public/pluginapi"
"github.com/mattermost/mattermost/server/public/pluginapi/experimental/bot/poster/mock_import"
)
const (
botID = "test-bot-user"
userID = "test-user-1"
dmChannelID = "dm-channel-id"
)
func TestInterface(t *testing.T) {
t.Run("Plugin API satisfy the interface", func(t *testing.T) {
api := &plugintest.API{}
driver := &plugintest.Driver{}
client := pluginapi.NewClient(api, driver)
_ = NewPoster(&client.Post, botID)
})
}
func TestDM(t *testing.T) {
format := "test format, string: %s int: %d value: %v"
args := []interface{}{"some string", 5, 8.423}
expectedMessage := "test format, string: some string int: 5 value: 8.423"
expectedPostID := "expected-post-id"
post := &model.Post{
Message: expectedMessage,
}
postWithID := model.Post{
Id: expectedPostID,
UserId: botID,
ChannelId: dmChannelID,
Message: expectedMessage,
}
mockError := errors.New("mock error")
t.Run("DM Success", func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
postAPI := mock_import.NewMockPostAPI(ctrl)
poster := NewPoster(postAPI, botID)
//nolint:govet //copy lock, but only used in tests
postAPI.
EXPECT().
DM(botID, userID, post).
SetArg(2, postWithID).
Return(nil).
Times(1)
postID, err := poster.DM(userID, format, args...)
assert.Equal(t, expectedPostID, postID)
assert.NoError(t, err)
})
t.Run("DM error", func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
postAPI := mock_import.NewMockPostAPI(ctrl)
poster := NewPoster(postAPI, botID)
postAPI.
EXPECT().
DM(botID, userID, post).
Return(mockError).
Times(1)
_, err := poster.DM(userID, format, args...)
assert.Error(t, err)
})
}
func TestDMWithAttachments(t *testing.T) {
expectedPostID := "expected-post-id"
attachments := []*model.SlackAttachment{
{},
{},
}
post := &model.Post{}
model.ParseSlackAttachment(post, attachments)
postWithID := model.Post{
Id: expectedPostID,
UserId: botID,
ChannelId: dmChannelID,
Type: model.PostTypeSlackAttachment,
Props: model.StringInterface{
"attachments": attachments,
},
}
mockError := errors.New("mock error")
t.Run("DM Success", func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
postAPI := mock_import.NewMockPostAPI(ctrl)
poster := NewPoster(postAPI, botID)
//nolint:govet //copy lock, but only used in tests
postAPI.
EXPECT().
DM(botID, userID, post).
SetArg(2, postWithID).
Return(nil).
Times(1)
postID, err := poster.DMWithAttachments(userID, attachments...)
assert.Equal(t, expectedPostID, postID)
assert.NoError(t, err)
})
t.Run("DM error", func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
postAPI := mock_import.NewMockPostAPI(ctrl)
poster := NewPoster(postAPI, botID)
postAPI.
EXPECT().
DM(botID, userID, post).
Return(mockError).
Times(1)
_, err := poster.DMWithAttachments(userID, attachments...)
assert.Error(t, err)
})
}
func TestEphemeral(t *testing.T) {
format := "test format, string: %s int: %d value: %v"
args := []interface{}{"some string", 5, 8.423}
expectedMessage := "test format, string: some string int: 5 value: 8.423"
channelID := "some-channel"
post := &model.Post{
UserId: botID,
ChannelId: channelID,
Message: expectedMessage,
}
expectedPostID := "some-post-ID"
postWithID := model.Post{
Id: expectedPostID,
UserId: botID,
ChannelId: channelID,
Message: expectedMessage,
}
t.Run("Success", func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
postAPI := mock_import.NewMockPostAPI(ctrl)
poster := NewPoster(postAPI, botID)
//nolint:govet //copy lock, but only used in tests
postAPI.
EXPECT().
SendEphemeralPost(userID, post).
SetArg(1, postWithID).
Times(1)
poster.Ephemeral(userID, channelID, format, args...)
})
}
func TestUpdatePostByID(t *testing.T) {
format := "test format, string: %s int: %d value: %v"
args := []interface{}{"some string", 5, 8.423}
expectedMessage := "test format, string: some string int: 5 value: 8.423"
postID := "some-post-id"
originalPost := &model.Post{
Id: postID,
Message: "some message",
}
updatedPost := &model.Post{
Id: postID,
Message: expectedMessage,
}
mockError := errors.New("mock error")
t.Run("Success", func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
postAPI := mock_import.NewMockPostAPI(ctrl)
poster := NewPoster(postAPI, botID)
postAPI.
EXPECT().
GetPost(postID).
Return(originalPost, nil).
Times(1)
postAPI.
EXPECT().
UpdatePost(updatedPost).
Return(nil).
Times(1)
err := poster.UpdatePostByID(postID, format, args...)
assert.NoError(t, err)
})
t.Run("Error fetching", func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
postAPI := mock_import.NewMockPostAPI(ctrl)
poster := NewPoster(postAPI, botID)
postAPI.
EXPECT().
GetPost(postID).
Return(nil, mockError).
Times(1)
err := poster.UpdatePostByID(postID, format, args...)
assert.Error(t, err)
})
t.Run("Error updating", func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
postAPI := mock_import.NewMockPostAPI(ctrl)
poster := NewPoster(postAPI, botID)
postAPI.
EXPECT().
GetPost(postID).
Return(originalPost, nil).
Times(1)
postAPI.
EXPECT().
UpdatePost(updatedPost).
Return(mockError).
Times(1)
err := poster.UpdatePostByID(postID, format, args...)
assert.Error(t, err)
})
}
func TestDeletePost(t *testing.T) {
postID := "some-post-id"
mockError := errors.New("mock channel error")
t.Run("Success", func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
postAPI := mock_import.NewMockPostAPI(ctrl)
poster := NewPoster(postAPI, botID)
postAPI.
EXPECT().
DeletePost(postID).
Return(nil).
Times(1)
err := poster.DeletePost(postID)
assert.NoError(t, err)
})
t.Run("Error", func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
postAPI := mock_import.NewMockPostAPI(ctrl)
poster := NewPoster(postAPI, botID)
postAPI.
EXPECT().
DeletePost(postID).
Return(mockError).
Times(1)
err := poster.DeletePost(postID)
assert.Error(t, err)
})
}
func TestUpdatePost(t *testing.T) {
post := &model.Post{
Id: "some-post-id",
Message: "some message",
}
mockError := errors.New("mock channel error")
t.Run("Success", func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
postAPI := mock_import.NewMockPostAPI(ctrl)
poster := NewPoster(postAPI, botID)
postAPI.
EXPECT().
UpdatePost(post).
Return(nil).
Times(1)
err := poster.UpdatePost(post)
assert.NoError(t, err)
})
t.Run("Error", func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
postAPI := mock_import.NewMockPostAPI(ctrl)
poster := NewPoster(postAPI, botID)
postAPI.
EXPECT().
UpdatePost(post).
Return(mockError).
Times(1)
err := poster.UpdatePost(post)
assert.Error(t, err)
})
}
func TestUpdatePosterID(t *testing.T) {
format := "test format, string: %s int: %d value: %v"
args := []interface{}{"some string", 5, 8.423}
expectedMessage := "test format, string: some string int: 5 value: 8.423"
expectedPostID := "expected-post-id"
post := &model.Post{
Message: expectedMessage,
}
postWithID := model.Post{
Id: expectedPostID,
UserId: botID,
ChannelId: dmChannelID,
Message: expectedMessage,
}
newBotID := "new-bot-id"
t.Run("Success", func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
postAPI := mock_import.NewMockPostAPI(ctrl)
poster := NewPoster(postAPI, botID)
//nolint:govet //copy lock, but only used in tests
postAPI.
EXPECT().
DM(botID, userID, post).
SetArg(2, postWithID).
Return(nil).
Times(1)
_, _ = poster.DM(userID, format, args...)
poster.UpdatePosterID(newBotID)
//nolint:govet //copy lock, but only used in tests
postAPI.
EXPECT().
DM(newBotID, userID, post).
SetArg(2, postWithID).
Return(nil).
Times(1)
_, _ = poster.DM(userID, format, args...)
})
}

Просмотреть файл

@@ -0,0 +1,14 @@
package poster
import (
"github.com/mattermost/mattermost/server/public/model"
)
// PostAPI defines the portion of the Post Service used by the poster
type PostAPI interface {
DM(senderUserID, receiverUserID string, post *model.Post) error
GetPost(postID string) (*model.Post, error)
UpdatePost(post *model.Post) error
DeletePost(postID string) error
SendEphemeralPost(userID string, post *model.Post)
}

Просмотреть файл

@@ -0,0 +1,104 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/mattermost/mattermost/server/public/pluginapi/experimental/bot/poster (interfaces: PostAPI)
// Package mock_import is a generated GoMock package.
package mock_import
import (
reflect "reflect"
gomock "github.com/golang/mock/gomock"
model "github.com/mattermost/mattermost/server/public/model"
)
// MockPostAPI is a mock of PostAPI interface.
type MockPostAPI struct {
ctrl *gomock.Controller
recorder *MockPostAPIMockRecorder
}
// MockPostAPIMockRecorder is the mock recorder for MockPostAPI.
type MockPostAPIMockRecorder struct {
mock *MockPostAPI
}
// NewMockPostAPI creates a new mock instance.
func NewMockPostAPI(ctrl *gomock.Controller) *MockPostAPI {
mock := &MockPostAPI{ctrl: ctrl}
mock.recorder = &MockPostAPIMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockPostAPI) EXPECT() *MockPostAPIMockRecorder {
return m.recorder
}
// DM mocks base method.
func (m *MockPostAPI) DM(arg0, arg1 string, arg2 *model.Post) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DM", arg0, arg1, arg2)
ret0, _ := ret[0].(error)
return ret0
}
// DM indicates an expected call of DM.
func (mr *MockPostAPIMockRecorder) DM(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DM", reflect.TypeOf((*MockPostAPI)(nil).DM), arg0, arg1, arg2)
}
// DeletePost mocks base method.
func (m *MockPostAPI) DeletePost(arg0 string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DeletePost", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// DeletePost indicates an expected call of DeletePost.
func (mr *MockPostAPIMockRecorder) DeletePost(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeletePost", reflect.TypeOf((*MockPostAPI)(nil).DeletePost), arg0)
}
// GetPost mocks base method.
func (m *MockPostAPI) GetPost(arg0 string) (*model.Post, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetPost", arg0)
ret0, _ := ret[0].(*model.Post)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetPost indicates an expected call of GetPost.
func (mr *MockPostAPIMockRecorder) GetPost(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPost", reflect.TypeOf((*MockPostAPI)(nil).GetPost), arg0)
}
// SendEphemeralPost mocks base method.
func (m *MockPostAPI) SendEphemeralPost(arg0 string, arg1 *model.Post) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "SendEphemeralPost", arg0, arg1)
}
// SendEphemeralPost indicates an expected call of SendEphemeralPost.
func (mr *MockPostAPIMockRecorder) SendEphemeralPost(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendEphemeralPost", reflect.TypeOf((*MockPostAPI)(nil).SendEphemeralPost), arg0, arg1)
}
// UpdatePost mocks base method.
func (m *MockPostAPI) UpdatePost(arg0 *model.Post) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "UpdatePost", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// UpdatePost indicates an expected call of UpdatePost.
func (mr *MockPostAPIMockRecorder) UpdatePost(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdatePost", reflect.TypeOf((*MockPostAPI)(nil).UpdatePost), arg0)
}

Просмотреть файл

@@ -0,0 +1,38 @@
// Copyright (c) 2019-present Mattermost, Inc. All Rights Reserved.
// See License for license information.
package poster
import (
"github.com/mattermost/mattermost/server/public/model"
)
// Poster defines an entity that can post DMs and Ephemerals and update and delete those posts
type Poster interface {
DMer
// DMWithAttachments posts a Direct Message that contains Slack attachments.
// Often used to include post actions.
DMWithAttachments(mattermostUserID string, attachments ...*model.SlackAttachment) (string, error)
// Ephemeral sends an ephemeral message to a user
Ephemeral(mattermostUserID, channelID, format string, args ...interface{})
// UpdatePostByID updates the post with postID with the formatted message
UpdatePostByID(postID, format string, args ...interface{}) error
// DeletePost deletes a single post
DeletePost(postID string) error
// DMUpdatePost substitute one post with another
UpdatePost(post *model.Post) error
// UpdatePosterID updates the Mattermost User ID of the poster
UpdatePosterID(id string)
}
// DMer defines an entity that can send Direct Messages
type DMer interface {
// DM posts a simple Direct Message to the specified user
DM(mattermostUserID, format string, args ...interface{}) (string, error)
}