939 lines
30 KiB
Go
939 lines
30 KiB
Go
package main
|
||
|
||
import (
|
||
"errors"
|
||
"fmt"
|
||
|
||
"github.com/larkox/mattermost-plugin-badges/badgesmodel"
|
||
commandparser "github.com/larkox/mattermost-plugin-badges/server/command_parser"
|
||
"github.com/mattermost/mattermost-server/v5/model"
|
||
"github.com/mattermost/mattermost-server/v5/plugin"
|
||
"github.com/spf13/pflag"
|
||
)
|
||
|
||
func getHelp() string {
|
||
return `Available Commands:
|
||
`
|
||
}
|
||
|
||
func (p *Plugin) getCommand() *model.Command {
|
||
return &model.Command{
|
||
Trigger: "badges",
|
||
DisplayName: "Achievements Bot",
|
||
Description: "Achievements",
|
||
AutoComplete: true,
|
||
AutoCompleteDesc: "Available commands:",
|
||
AutoCompleteHint: "[command]",
|
||
AutocompleteData: p.getAutocompleteData(),
|
||
}
|
||
}
|
||
|
||
func (p *Plugin) postCommandResponse(args *model.CommandArgs, text string) {
|
||
post := &model.Post{
|
||
UserId: p.BotUserID,
|
||
ChannelId: args.ChannelId,
|
||
Message: text,
|
||
}
|
||
p.mm.Post.SendEphemeralPost(args.UserId, post)
|
||
}
|
||
|
||
func commandError(text string) (bool, *model.CommandResponse, error) {
|
||
return true, &model.CommandResponse{}, errors.New(text)
|
||
}
|
||
|
||
// ExecuteCommand executes a given command and returns a command response.
|
||
func (p *Plugin) ExecuteCommand(c *plugin.Context, args *model.CommandArgs) (*model.CommandResponse, *model.AppError) {
|
||
stringArgs := commandparser.Parse(args.Command)
|
||
lengthOfArgs := len(stringArgs)
|
||
restOfArgs := []string{}
|
||
|
||
var handler func([]string, *model.CommandArgs) (bool, *model.CommandResponse, error)
|
||
if lengthOfArgs == 1 {
|
||
p.postCommandResponse(args, getHelp())
|
||
return &model.CommandResponse{}, nil
|
||
}
|
||
command := stringArgs[1]
|
||
if lengthOfArgs > 2 {
|
||
restOfArgs = stringArgs[2:]
|
||
}
|
||
switch command {
|
||
case "test-clean":
|
||
handler = p.runClean
|
||
case "grant":
|
||
handler = p.runGrant
|
||
case "edit":
|
||
handler = p.runEdit
|
||
case "create":
|
||
handler = p.runCreate
|
||
case "subscription":
|
||
handler = p.runSubscription
|
||
default:
|
||
p.postCommandResponse(args, getHelp())
|
||
return &model.CommandResponse{}, nil
|
||
}
|
||
isUserError, resp, err := handler(restOfArgs, args)
|
||
if err != nil {
|
||
if isUserError {
|
||
p.postCommandResponse(args, fmt.Sprintf("__Error: %s__", err.Error()))
|
||
} else {
|
||
p.mm.Log.Error(err.Error())
|
||
u, _ := p.mm.User.Get(args.UserId)
|
||
locale := "ru"
|
||
if u != nil {
|
||
locale = u.Locale
|
||
}
|
||
T := p.getT(locale)
|
||
p.postCommandResponse(args, T("badges.error.unknown", "Произошла неизвестная ошибка. Обратитесь к системному администратору."))
|
||
}
|
||
}
|
||
|
||
if resp != nil {
|
||
return resp, nil
|
||
}
|
||
|
||
return &model.CommandResponse{}, nil
|
||
}
|
||
|
||
func (p *Plugin) runClean(args []string, extra *model.CommandArgs) (bool, *model.CommandResponse, error) {
|
||
user, err := p.mm.User.Get(extra.UserId)
|
||
if err != nil {
|
||
return false, &model.CommandResponse{Text: "Cannot get user."}, nil
|
||
}
|
||
T := p.getT(user.Locale)
|
||
if !user.IsSystemAdmin() {
|
||
return false, &model.CommandResponse{Text: T("badges.error.only_sysadmin_clean", "Только системный администратор может очистить базу значков.")}, nil
|
||
}
|
||
_ = p.mm.KV.DeleteAll()
|
||
return false, &model.CommandResponse{Text: T("badges.success.clean", "Очищено")}, nil
|
||
}
|
||
|
||
func (p *Plugin) runCreate(args []string, extra *model.CommandArgs) (bool, *model.CommandResponse, error) {
|
||
lengthOfArgs := len(args)
|
||
restOfArgs := []string{}
|
||
var handler func([]string, *model.CommandArgs) (bool, *model.CommandResponse, error)
|
||
if lengthOfArgs == 0 {
|
||
u, _ := p.mm.User.Get(extra.UserId)
|
||
locale := "ru"
|
||
if u != nil {
|
||
locale = u.Locale
|
||
}
|
||
T := p.getT(locale)
|
||
return false, &model.CommandResponse{Text: T("badges.error.specify_create", "Укажите, что вы хотите создать.")}, nil
|
||
}
|
||
command := args[0]
|
||
if lengthOfArgs > 1 {
|
||
restOfArgs = args[1:]
|
||
}
|
||
switch command {
|
||
case "badge":
|
||
handler = p.runCreateBadge
|
||
case "type":
|
||
handler = p.runCreateType
|
||
default:
|
||
u, _ := p.mm.User.Get(extra.UserId)
|
||
locale := "ru"
|
||
if u != nil {
|
||
locale = u.Locale
|
||
}
|
||
T := p.getT(locale)
|
||
return false, &model.CommandResponse{Text: T("badges.error.create_badge_or_type", "Можно создать badge или type")}, nil
|
||
}
|
||
|
||
return handler(restOfArgs, extra)
|
||
}
|
||
|
||
func (p *Plugin) runCreateBadge(args []string, extra *model.CommandArgs) (bool, *model.CommandResponse, error) {
|
||
u, err := p.mm.User.Get(extra.UserId)
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
T := p.getT(u.Locale)
|
||
|
||
typeSuggestions, err := p.filterCreateBadgeTypes(u)
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
|
||
typeOptions := []*model.PostActionOptions{}
|
||
for _, typeSuggestion := range typeSuggestions {
|
||
id := string(typeSuggestion.ID)
|
||
typeOptions = append(typeOptions, &model.PostActionOptions{Text: typeSuggestion.Name, Value: id})
|
||
}
|
||
|
||
if len(typeOptions) == 0 {
|
||
return commandError(T("badges.error.no_types_available", "Вы не можете создать значки ни одного типа."))
|
||
}
|
||
|
||
err = p.mm.Frontend.OpenInteractiveDialog(model.OpenDialogRequest{
|
||
TriggerId: extra.TriggerId,
|
||
URL: p.getDialogURL() + DialogPathCreateBadge,
|
||
Dialog: model.Dialog{
|
||
Title: T("badges.dialog.create_badge.title", "Создать значок"),
|
||
SubmitLabel: T("badges.dialog.create_badge.submit", "Создать"),
|
||
Elements: []model.DialogElement{
|
||
{
|
||
DisplayName: T("badges.field.name", "Название"),
|
||
Type: "text",
|
||
Name: DialogFieldBadgeName,
|
||
MaxLength: badgesmodel.NameMaxLength,
|
||
},
|
||
{
|
||
DisplayName: T("badges.field.description", "Описание"),
|
||
Type: "text",
|
||
Name: DialogFieldBadgeDescription,
|
||
MaxLength: badgesmodel.DescriptionMaxLength,
|
||
},
|
||
{
|
||
DisplayName: T("badges.field.image", "Изображение"),
|
||
Type: "text",
|
||
Name: DialogFieldBadgeImage,
|
||
HelpText: T("badges.field.image.help", "Введите название эмодзи"),
|
||
},
|
||
{
|
||
DisplayName: T("badges.field.type", "Тип"),
|
||
Type: "select",
|
||
Name: DialogFieldBadgeType,
|
||
Options: typeOptions,
|
||
},
|
||
{
|
||
DisplayName: T("badges.field.multiple", "Многократный"),
|
||
Type: "bool",
|
||
Name: DialogFieldBadgeMultiple,
|
||
HelpText: T("badges.field.multiple.help", "Можно ли выдавать этот значок несколько раз"),
|
||
Optional: true,
|
||
},
|
||
},
|
||
},
|
||
})
|
||
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
|
||
return false, &model.CommandResponse{}, nil
|
||
}
|
||
|
||
func (p *Plugin) runEdit(args []string, extra *model.CommandArgs) (bool, *model.CommandResponse, error) {
|
||
lengthOfArgs := len(args)
|
||
restOfArgs := []string{}
|
||
var handler func([]string, *model.CommandArgs) (bool, *model.CommandResponse, error)
|
||
if lengthOfArgs == 0 {
|
||
u, _ := p.mm.User.Get(extra.UserId)
|
||
locale := "ru"
|
||
if u != nil {
|
||
locale = u.Locale
|
||
}
|
||
T := p.getT(locale)
|
||
return false, &model.CommandResponse{Text: T("badges.error.specify_edit", "Укажите, что вы хотите отредактировать.")}, nil
|
||
}
|
||
command := args[0]
|
||
if lengthOfArgs > 1 {
|
||
restOfArgs = args[1:]
|
||
}
|
||
switch command {
|
||
case "badge":
|
||
handler = p.runEditBadge
|
||
case "type":
|
||
handler = p.runEditType
|
||
default:
|
||
u, _ := p.mm.User.Get(extra.UserId)
|
||
locale := "ru"
|
||
if u != nil {
|
||
locale = u.Locale
|
||
}
|
||
T := p.getT(locale)
|
||
return false, &model.CommandResponse{Text: T("badges.error.edit_badge_or_type", "Можно редактировать badge или type")}, nil
|
||
}
|
||
|
||
return handler(restOfArgs, extra)
|
||
}
|
||
|
||
func (p *Plugin) runEditBadge(args []string, extra *model.CommandArgs) (bool, *model.CommandResponse, error) {
|
||
u, err := p.mm.User.Get(extra.UserId)
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
T := p.getT(u.Locale)
|
||
|
||
var badgeIDStr string
|
||
fs := pflag.NewFlagSet("", pflag.ContinueOnError)
|
||
fs.StringVar(&badgeIDStr, "id", "", "ID of the badge")
|
||
if err = fs.Parse(args); err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
|
||
if badgeIDStr == "" {
|
||
return commandError(T("badges.error.must_set_badge_id", "Необходимо указать ID значка"))
|
||
}
|
||
|
||
badge, err := p.store.GetBadge(badgesmodel.BadgeID(badgeIDStr))
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
|
||
if !canEditBadge(u, p.badgeAdminUserID, badge) {
|
||
return commandError(T("badges.error.cannot_edit_badge", "У вас нет прав на редактирование этого значка"))
|
||
}
|
||
|
||
typeSuggestions, err := p.filterCreateBadgeTypes(u)
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
|
||
typeOptions := []*model.PostActionOptions{}
|
||
for _, typeSuggestion := range typeSuggestions {
|
||
id := string(typeSuggestion.ID)
|
||
typeOptions = append(typeOptions, &model.PostActionOptions{Text: typeSuggestion.Name, Value: id})
|
||
}
|
||
|
||
if len(typeOptions) == 0 {
|
||
return commandError(T("badges.error.no_types_available", "Вы не можете создать значки ни одного типа."))
|
||
}
|
||
|
||
err = p.mm.Frontend.OpenInteractiveDialog(model.OpenDialogRequest{
|
||
TriggerId: extra.TriggerId,
|
||
URL: p.getDialogURL() + DialogPathEditBadge,
|
||
Dialog: model.Dialog{
|
||
Title: T("badges.dialog.edit_badge.title", "Редактировать значок"),
|
||
SubmitLabel: T("badges.dialog.edit_badge.submit", "Сохранить"),
|
||
State: string(badge.ID),
|
||
Elements: []model.DialogElement{
|
||
{
|
||
DisplayName: T("badges.field.name", "Название"),
|
||
Type: "text",
|
||
Name: DialogFieldBadgeName,
|
||
MaxLength: badgesmodel.NameMaxLength,
|
||
Default: badge.Name,
|
||
},
|
||
{
|
||
DisplayName: T("badges.field.description", "Описание"),
|
||
Type: "text",
|
||
Name: DialogFieldBadgeDescription,
|
||
MaxLength: badgesmodel.DescriptionMaxLength,
|
||
Default: badge.Description,
|
||
},
|
||
{
|
||
DisplayName: T("badges.field.image", "Изображение"),
|
||
Type: "text",
|
||
Name: DialogFieldBadgeImage,
|
||
HelpText: T("badges.field.image.help", "Введите название эмодзи"),
|
||
Default: badge.Image,
|
||
},
|
||
{
|
||
DisplayName: T("badges.field.type", "Тип"),
|
||
Type: "select",
|
||
Name: DialogFieldBadgeType,
|
||
Options: typeOptions,
|
||
Default: string(badge.Type),
|
||
},
|
||
{
|
||
DisplayName: T("badges.field.multiple", "Многократный"),
|
||
Type: "bool",
|
||
Name: DialogFieldBadgeMultiple,
|
||
HelpText: T("badges.field.multiple.help", "Можно ли выдавать этот значок несколько раз"),
|
||
Optional: true,
|
||
Default: getBooleanString(badge.Multiple),
|
||
},
|
||
{
|
||
DisplayName: T("badges.field.delete_badge", "Удалить значок"),
|
||
Type: "bool",
|
||
Name: DialogFieldBadgeDelete,
|
||
HelpText: T("badges.field.delete_badge.help", "ВНИМАНИЕ: если отметить, значок будет удалён безвозвратно."),
|
||
Optional: true,
|
||
},
|
||
},
|
||
},
|
||
})
|
||
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
|
||
return false, &model.CommandResponse{}, nil
|
||
}
|
||
|
||
func (p *Plugin) runEditType(args []string, extra *model.CommandArgs) (bool, *model.CommandResponse, error) {
|
||
u, err := p.mm.User.Get(extra.UserId)
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
T := p.getT(u.Locale)
|
||
|
||
if !canCreateType(u, p.badgeAdminUserID, false) {
|
||
return commandError(T("badges.error.no_permissions_edit_type", "У вас нет прав на редактирование типа значков."))
|
||
}
|
||
|
||
var badgeTypeStr string
|
||
fs := pflag.NewFlagSet("", pflag.ContinueOnError)
|
||
fs.StringVar(&badgeTypeStr, "type", "", "ID of the type")
|
||
if err = fs.Parse(args); err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
|
||
if badgeTypeStr == "" {
|
||
return commandError(T("badges.error.must_provide_type_id", "Необходимо указать ID типа"))
|
||
}
|
||
|
||
typeDefinition, err := p.store.GetType(badgesmodel.BadgeType(badgeTypeStr))
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
|
||
if !canEditType(u, p.badgeAdminUserID, typeDefinition) {
|
||
return commandError(T("badges.error.cannot_edit_type", "У вас нет прав на редактирование этого типа"))
|
||
}
|
||
|
||
canGrantAllowList := ""
|
||
for uID, allowed := range typeDefinition.CanGrant.AllowList {
|
||
if !allowed {
|
||
continue
|
||
}
|
||
var allowedUser *model.User
|
||
allowedUser, err = p.mm.User.Get(uID)
|
||
if err != nil {
|
||
continue
|
||
}
|
||
if canGrantAllowList == "" {
|
||
canGrantAllowList += allowedUser.Username
|
||
continue
|
||
}
|
||
|
||
canGrantAllowList += ", " + allowedUser.Username
|
||
}
|
||
|
||
canCreateAllowList := ""
|
||
for uID, allowed := range typeDefinition.CanCreate.AllowList {
|
||
if !allowed {
|
||
continue
|
||
}
|
||
var allowedUser *model.User
|
||
allowedUser, err = p.mm.User.Get(uID)
|
||
if err != nil {
|
||
continue
|
||
}
|
||
if canCreateAllowList == "" {
|
||
canCreateAllowList += allowedUser.Username
|
||
continue
|
||
}
|
||
|
||
canCreateAllowList += ", " + allowedUser.Username
|
||
}
|
||
|
||
err = p.mm.Frontend.OpenInteractiveDialog(model.OpenDialogRequest{
|
||
TriggerId: extra.TriggerId,
|
||
URL: p.getDialogURL() + DialogPathEditType,
|
||
Dialog: model.Dialog{
|
||
Title: T("badges.dialog.edit_type.title", "Редактировать тип"),
|
||
SubmitLabel: T("badges.dialog.edit_type.submit", "Сохранить"),
|
||
State: badgeTypeStr,
|
||
Elements: []model.DialogElement{
|
||
{
|
||
DisplayName: T("badges.field.name", "Название"),
|
||
Type: "text",
|
||
Name: DialogFieldTypeName,
|
||
MaxLength: badgesmodel.NameMaxLength,
|
||
Default: typeDefinition.Name,
|
||
},
|
||
{
|
||
DisplayName: T("badges.field.everyone_can_create", "Все могут создавать значки"),
|
||
Type: "bool",
|
||
Name: DialogFieldTypeEveryoneCanCreate,
|
||
HelpText: T("badges.field.everyone_can_create.help", "Любой пользователь может создать значок этого типа"),
|
||
Optional: true,
|
||
Default: getBooleanString(typeDefinition.CanCreate.Everyone),
|
||
},
|
||
{
|
||
DisplayName: T("badges.field.allowlist_create", "Список допущенных к созданию"),
|
||
Type: "text",
|
||
Name: DialogFieldTypeAllowlistCanCreate,
|
||
HelpText: T("badges.field.allowlist_create.help", "Укажите имена пользователей через запятую (,), которые могут создавать значки этого типа."),
|
||
Placeholder: "user-1, user-2, user-3",
|
||
Optional: true,
|
||
Default: canCreateAllowList,
|
||
},
|
||
{
|
||
DisplayName: T("badges.field.everyone_can_grant", "Все могут выдавать значки"),
|
||
Type: "bool",
|
||
Name: DialogFieldTypeEveryoneCanGrant,
|
||
HelpText: T("badges.field.everyone_can_grant.help", "Любой пользователь может выдать значок этого типа"),
|
||
Optional: true,
|
||
Default: getBooleanString(typeDefinition.CanGrant.Everyone),
|
||
},
|
||
{
|
||
DisplayName: T("badges.field.allowlist_grant", "Список допущенных к выдаче"),
|
||
Type: "text",
|
||
Name: DialogFieldTypeAllowlistCanGrant,
|
||
HelpText: T("badges.field.allowlist_grant.help", "Укажите имена пользователей через запятую (,), которые могут выдавать значки этого типа."),
|
||
Placeholder: "user-1, user-2, user-3",
|
||
Optional: true,
|
||
Default: canGrantAllowList,
|
||
},
|
||
{
|
||
DisplayName: T("badges.field.delete_type", "Удалить тип"),
|
||
Type: "bool",
|
||
Name: DialogFieldTypeDelete,
|
||
HelpText: T("badges.field.delete_type.help", "ВНИМАНИЕ: если отметить, этот тип и все связанные значки будут удалены безвозвратно."),
|
||
Optional: true,
|
||
},
|
||
},
|
||
},
|
||
})
|
||
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
|
||
return false, &model.CommandResponse{}, nil
|
||
}
|
||
|
||
func (p *Plugin) runCreateType(args []string, extra *model.CommandArgs) (bool, *model.CommandResponse, error) {
|
||
u, err := p.mm.User.Get(extra.UserId)
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
T := p.getT(u.Locale)
|
||
|
||
if !canCreateType(u, p.badgeAdminUserID, false) {
|
||
return commandError(T("badges.error.no_permissions_create_type", "У вас нет прав на создание типа значков."))
|
||
}
|
||
|
||
err = p.mm.Frontend.OpenInteractiveDialog(model.OpenDialogRequest{
|
||
TriggerId: extra.TriggerId,
|
||
URL: p.getDialogURL() + DialogPathCreateType,
|
||
Dialog: model.Dialog{
|
||
Title: T("badges.dialog.create_type.title", "Создать тип"),
|
||
SubmitLabel: T("badges.dialog.create_type.submit", "Создать"),
|
||
Elements: []model.DialogElement{
|
||
{
|
||
DisplayName: T("badges.field.name", "Название"),
|
||
Type: "text",
|
||
Name: DialogFieldTypeName,
|
||
MaxLength: badgesmodel.NameMaxLength,
|
||
},
|
||
{
|
||
DisplayName: T("badges.field.everyone_can_create", "Все могут создавать значки"),
|
||
Type: "bool",
|
||
Name: DialogFieldTypeEveryoneCanCreate,
|
||
HelpText: T("badges.field.everyone_can_create.help", "Любой пользователь может создать значок этого типа"),
|
||
Optional: true,
|
||
},
|
||
{
|
||
DisplayName: T("badges.field.allowlist_create", "Список допущенных к созданию"),
|
||
Type: "text",
|
||
Name: DialogFieldTypeAllowlistCanCreate,
|
||
HelpText: T("badges.field.allowlist_create.help", "Укажите имена пользователей через запятую (,), которые могут создавать значки этого типа."),
|
||
Placeholder: "user-1, user-2, user-3",
|
||
Optional: true,
|
||
},
|
||
{
|
||
DisplayName: T("badges.field.everyone_can_grant", "Все могут выдавать значки"),
|
||
Type: "bool",
|
||
Name: DialogFieldTypeEveryoneCanGrant,
|
||
HelpText: T("badges.field.everyone_can_grant.help", "Любой пользователь может выдать значок этого типа"),
|
||
Optional: true,
|
||
},
|
||
{
|
||
DisplayName: T("badges.field.allowlist_grant", "Список допущенных к выдаче"),
|
||
Type: "text",
|
||
Name: DialogFieldTypeAllowlistCanGrant,
|
||
HelpText: T("badges.field.allowlist_grant.help", "Укажите имена пользователей через запятую (,), которые могут выдавать значки этого типа."),
|
||
Placeholder: "user-1, user-2, user-3",
|
||
Optional: true,
|
||
},
|
||
},
|
||
},
|
||
})
|
||
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
|
||
return false, &model.CommandResponse{}, nil
|
||
}
|
||
|
||
func (p *Plugin) runGrant(args []string, extra *model.CommandArgs) (bool, *model.CommandResponse, error) {
|
||
badgeStr := ""
|
||
username := ""
|
||
fs := pflag.NewFlagSet("", pflag.ContinueOnError)
|
||
fs.StringVar(&badgeStr, "badge", "", "ID of the badge")
|
||
fs.StringVar(&username, "user", "", "Username to grant to")
|
||
if err := fs.Parse(args); err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
|
||
if username != "" && badgeStr != "" {
|
||
if username[0] == '@' {
|
||
username = username[1:]
|
||
}
|
||
|
||
granter, err := p.mm.User.Get(extra.UserId)
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
T := p.getT(granter.Locale)
|
||
|
||
badge, err := p.store.GetBadge(badgesmodel.BadgeID(badgeStr))
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
|
||
badgeType, err := p.store.GetType(badge.Type)
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
|
||
if !canGrantBadge(granter, p.badgeAdminUserID, badge, badgeType) {
|
||
return commandError(T("badges.error.no_permissions_grant", "У вас нет прав на выдачу этого значка"))
|
||
}
|
||
|
||
user, err := p.mm.User.GetByUsername(username)
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
|
||
shouldNotify, err := p.store.GrantBadge(badgesmodel.BadgeID(badgeStr), user.Id, extra.UserId, "")
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
|
||
if shouldNotify {
|
||
p.notifyGrant(badgesmodel.BadgeID(badgeStr), extra.UserId, user, false, "", "")
|
||
}
|
||
|
||
p.postCommandResponse(extra, T("badges.success.granted", "Выдано"))
|
||
return false, &model.CommandResponse{}, nil
|
||
}
|
||
|
||
actingUser, err := p.mm.User.Get(extra.UserId)
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
T := p.getT(actingUser.Locale)
|
||
|
||
elements := []model.DialogElement{}
|
||
|
||
stateText := ""
|
||
introductionText := ""
|
||
if username != "" {
|
||
if username[0] == '@' {
|
||
username = username[1:]
|
||
}
|
||
|
||
user, err := p.mm.User.GetByUsername(username)
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
|
||
introductionText = T("badges.dialog.grant.intro", "Выдать значок пользователю @%s", username)
|
||
stateText = user.Id
|
||
}
|
||
|
||
if stateText == "" {
|
||
elements = append(elements, model.DialogElement{
|
||
DisplayName: T("badges.field.user", "Пользователь"),
|
||
Type: "select",
|
||
Name: DialogFieldUser,
|
||
DataSource: "users",
|
||
})
|
||
}
|
||
|
||
options := []*model.PostActionOptions{}
|
||
grantableBadges, err := p.filterGrantBadges(actingUser)
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
for _, badge := range grantableBadges {
|
||
options = append(options, &model.PostActionOptions{Text: badge.Name, Value: string(badge.ID)})
|
||
}
|
||
|
||
badgeElement := model.DialogElement{
|
||
DisplayName: T("badges.field.badge", "Значок"),
|
||
Type: "select",
|
||
Name: DialogFieldBadge,
|
||
Options: options,
|
||
}
|
||
|
||
if badgeStr != "" {
|
||
found := false
|
||
for _, badge := range grantableBadges {
|
||
if badgeStr == string(badge.ID) {
|
||
found = true
|
||
break
|
||
}
|
||
}
|
||
|
||
if !found {
|
||
return commandError(T("badges.error.cannot_grant_badge", "Вы не можете выдать этот значок"))
|
||
}
|
||
|
||
badgeElement.Default = badgeStr
|
||
}
|
||
|
||
elements = append(elements, badgeElement)
|
||
|
||
elements = append(elements, model.DialogElement{
|
||
DisplayName: T("badges.field.reason", "Причина"),
|
||
Name: DialogFieldGrantReason,
|
||
Optional: true,
|
||
HelpText: T("badges.field.reason.help", "Причина выдачи значка. Будет видна пользователю и в уведомлениях о выдаче (например, в подписках)."),
|
||
Type: "text",
|
||
})
|
||
|
||
elements = append(elements, model.DialogElement{
|
||
DisplayName: T("badges.field.notify_here", "Уведомить в этом канале"),
|
||
Name: DialogFieldNotifyHere,
|
||
Type: "bool",
|
||
HelpText: T("badges.field.notify_here.help", "Если отметить, бот отправит сообщение в этот канал о том, что вы выдали значок этому пользователю."),
|
||
Optional: true,
|
||
})
|
||
|
||
err = p.mm.Frontend.OpenInteractiveDialog(model.OpenDialogRequest{
|
||
TriggerId: extra.TriggerId,
|
||
URL: p.getDialogURL() + DialogPathGrant,
|
||
Dialog: model.Dialog{
|
||
Title: T("badges.dialog.grant.title", "Выдать значок"),
|
||
IntroductionText: introductionText,
|
||
SubmitLabel: T("badges.dialog.grant.submit", "Выдать"),
|
||
Elements: elements,
|
||
State: stateText,
|
||
},
|
||
})
|
||
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
|
||
return false, &model.CommandResponse{}, nil
|
||
}
|
||
|
||
func (p *Plugin) runSubscription(args []string, extra *model.CommandArgs) (bool, *model.CommandResponse, error) {
|
||
lengthOfArgs := len(args)
|
||
restOfArgs := []string{}
|
||
var handler func([]string, *model.CommandArgs) (bool, *model.CommandResponse, error)
|
||
if lengthOfArgs == 0 {
|
||
u, _ := p.mm.User.Get(extra.UserId)
|
||
locale := "ru"
|
||
if u != nil {
|
||
locale = u.Locale
|
||
}
|
||
T := p.getT(locale)
|
||
return false, &model.CommandResponse{Text: T("badges.error.specify_subscription", "Укажите, что вы хотите сделать.")}, nil
|
||
}
|
||
command := args[0]
|
||
if lengthOfArgs > 1 {
|
||
restOfArgs = args[1:]
|
||
}
|
||
switch command {
|
||
case "create":
|
||
handler = p.runCreateSubscription
|
||
case "remove":
|
||
handler = p.runDeleteSubscription
|
||
default:
|
||
u, _ := p.mm.User.Get(extra.UserId)
|
||
locale := "ru"
|
||
if u != nil {
|
||
locale = u.Locale
|
||
}
|
||
T := p.getT(locale)
|
||
return false, &model.CommandResponse{Text: T("badges.error.create_or_delete_subscription", "Можно создать или удалить подписку")}, nil
|
||
}
|
||
|
||
return handler(restOfArgs, extra)
|
||
}
|
||
|
||
func (p *Plugin) runCreateSubscription(args []string, extra *model.CommandArgs) (bool, *model.CommandResponse, error) {
|
||
typeStr := ""
|
||
fs := pflag.NewFlagSet("", pflag.ContinueOnError)
|
||
fs.StringVar(&typeStr, "type", "", "ID of the badge")
|
||
if err := fs.Parse(args); err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
|
||
actingUser, err := p.mm.User.Get(extra.UserId)
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
T := p.getT(actingUser.Locale)
|
||
|
||
if !canCreateSubscription(actingUser, p.badgeAdminUserID, extra.ChannelId) {
|
||
return commandError(T("badges.error.cannot_create_subscription", "Вы не можете создавать подписки"))
|
||
}
|
||
|
||
if typeStr != "" {
|
||
|
||
err = p.store.AddSubscription(badgesmodel.BadgeType(typeStr), extra.ChannelId)
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
|
||
p.postCommandResponse(extra, T("badges.success.granted", "Выдано"))
|
||
return false, &model.CommandResponse{}, nil
|
||
}
|
||
|
||
options := []*model.PostActionOptions{}
|
||
typesDefinitions, err := p.filterEditTypes(actingUser)
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
for _, typeDefinition := range typesDefinitions {
|
||
options = append(options, &model.PostActionOptions{Text: typeDefinition.Name, Value: string(typeDefinition.ID)})
|
||
}
|
||
|
||
err = p.mm.Frontend.OpenInteractiveDialog(model.OpenDialogRequest{
|
||
TriggerId: extra.TriggerId,
|
||
URL: p.getDialogURL() + DialogPathCreateSubscription,
|
||
Dialog: model.Dialog{
|
||
Title: T("badges.dialog.create_subscription.title", "Создать подписку"),
|
||
IntroductionText: T("badges.dialog.create_subscription.intro", "Выберите тип значка, на который хотите подписать этот канал."),
|
||
SubmitLabel: T("badges.dialog.create_subscription.submit", "Добавить"),
|
||
Elements: []model.DialogElement{
|
||
{
|
||
DisplayName: T("badges.field.type", "Тип"),
|
||
Type: "select",
|
||
Name: DialogFieldBadgeType,
|
||
Options: options,
|
||
},
|
||
},
|
||
},
|
||
})
|
||
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
|
||
return false, &model.CommandResponse{}, nil
|
||
}
|
||
|
||
func (p *Plugin) runDeleteSubscription(args []string, extra *model.CommandArgs) (bool, *model.CommandResponse, error) {
|
||
typeStr := ""
|
||
fs := pflag.NewFlagSet("", pflag.ContinueOnError)
|
||
fs.StringVar(&typeStr, "type", "", "ID of the badge")
|
||
if err := fs.Parse(args); err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
|
||
actingUser, err := p.mm.User.Get(extra.UserId)
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
T := p.getT(actingUser.Locale)
|
||
|
||
if !canCreateSubscription(actingUser, p.badgeAdminUserID, extra.ChannelId) {
|
||
return commandError(T("badges.error.cannot_create_subscription", "Вы не можете создавать подписки"))
|
||
}
|
||
|
||
if typeStr != "" {
|
||
err = p.store.RemoveSubscriptions(badgesmodel.BadgeType(typeStr), extra.ChannelId)
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
|
||
p.postCommandResponse(extra, T("badges.success.removed", "Удалено"))
|
||
return false, &model.CommandResponse{}, nil
|
||
}
|
||
|
||
options := []*model.PostActionOptions{}
|
||
typesDefinitions, err := p.store.GetChannelSubscriptions(extra.ChannelId)
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
for _, typeDefinition := range typesDefinitions {
|
||
options = append(options, &model.PostActionOptions{Text: typeDefinition.Name, Value: string(typeDefinition.ID)})
|
||
}
|
||
|
||
err = p.mm.Frontend.OpenInteractiveDialog(model.OpenDialogRequest{
|
||
TriggerId: extra.TriggerId,
|
||
URL: p.getDialogURL() + DialogPathDeleteSubscription,
|
||
Dialog: model.Dialog{
|
||
Title: T("badges.dialog.delete_subscription.title", "Удалить подписку"),
|
||
IntroductionText: T("badges.dialog.delete_subscription.intro", "Выберите тип значка, подписку на который хотите удалить из этого канала."),
|
||
SubmitLabel: T("badges.dialog.delete_subscription.submit", "Удалить"),
|
||
Elements: []model.DialogElement{
|
||
{
|
||
DisplayName: T("badges.field.type", "Тип"),
|
||
Type: "select",
|
||
Name: DialogFieldBadgeType,
|
||
Options: options,
|
||
},
|
||
},
|
||
},
|
||
})
|
||
|
||
if err != nil {
|
||
return commandError(err.Error())
|
||
}
|
||
|
||
return false, &model.CommandResponse{}, nil
|
||
}
|
||
|
||
func (p *Plugin) getAutocompleteData() *model.AutocompleteData {
|
||
badges := model.NewAutocompleteData("badges", "[command]", "Available commands: grant")
|
||
|
||
grant := model.NewAutocompleteData("grant", "--user @username --badge id", "Grant a badge to a user")
|
||
grant.AddNamedDynamicListArgument("badge", "--badge badgeID", getAutocompletePath(AutocompletePathBadgeSuggestions), true)
|
||
grant.AddNamedTextArgument("user", "User to grant the badge to", "--user @username", "", true)
|
||
badges.AddCommand(grant)
|
||
|
||
create := model.NewAutocompleteData("create", "badge | type", "Create a badge or a type")
|
||
|
||
badge := model.NewAutocompleteData(
|
||
"badge",
|
||
"",
|
||
"Create a badge",
|
||
)
|
||
create.AddCommand(badge)
|
||
|
||
createType := model.NewAutocompleteData(
|
||
"type",
|
||
"",
|
||
"Create a badge type",
|
||
)
|
||
create.AddCommand(createType)
|
||
|
||
badges.AddCommand(create)
|
||
|
||
edit := model.NewAutocompleteData("edit", "badge | type", "Edit a badge or a type")
|
||
|
||
editBadge := model.NewAutocompleteData(
|
||
"badge",
|
||
"",
|
||
"Edit a badge",
|
||
)
|
||
editBadge.AddNamedDynamicListArgument("id", "--id badgeID", getAutocompletePath(AutocompletePathEditBadgeSuggestions), true)
|
||
edit.AddCommand(editBadge)
|
||
|
||
editType := model.NewAutocompleteData(
|
||
"type",
|
||
"",
|
||
"Edit a badge type",
|
||
)
|
||
editType.AddNamedDynamicListArgument("type", "--type typeID", getAutocompletePath(AutocompletePathEditTypeSuggestions), true)
|
||
edit.AddCommand(editType)
|
||
|
||
badges.AddCommand(edit)
|
||
|
||
subscription := model.NewAutocompleteData("subscription", "create | remove", "Manage this channel subscriptions")
|
||
|
||
createSubscription := model.NewAutocompleteData(
|
||
"create",
|
||
"",
|
||
"Create a subscription",
|
||
)
|
||
subscription.AddCommand(createSubscription)
|
||
|
||
deleteSubscription := model.NewAutocompleteData(
|
||
"remove",
|
||
"",
|
||
"Remove a subscription",
|
||
)
|
||
subscription.AddCommand(deleteSubscription)
|
||
|
||
badges.AddCommand(subscription)
|
||
|
||
return badges
|
||
}
|
||
|
||
func getAutocompletePath(path string) string {
|
||
return "plugins/" + manifest.Id + AutocompletePath + path
|
||
}
|