From 7c976233a787e4d65559d89df07fa7102d2a93ff Mon Sep 17 00:00:00 2001 From: "dmitrii.pichenikin" Date: Thu, 19 Feb 2026 16:21:52 +0300 Subject: [PATCH] added the ability to assign multiple plugin administrators --- server/api.go | 32 ++++++++++++++++---------------- server/command.go | 14 +++++++------- server/configuration.go | 18 +++++++++++++----- server/plugin.go | 2 +- server/suggestions.go | 8 ++++---- server/utils.go | 24 ++++++++++++------------ 6 files changed, 53 insertions(+), 45 deletions(-) diff --git a/server/api.go b/server/api.go index 42e21b2..ab19455 100644 --- a/server/api.go +++ b/server/api.go @@ -172,7 +172,7 @@ func (p *Plugin) getTypes(w http.ResponseWriter, r *http.Request, userID string) resp := GetTypesResponse{ Types: result, - CanCreateType: canCreateType(u, p.badgeAdminUserID, false), + CanCreateType: canCreateType(u, p.badgeAdminUserIDs, false), } b, _ := json.Marshal(resp) @@ -225,7 +225,7 @@ func (p *Plugin) apiCreateBadge(w http.ResponseWriter, r *http.Request, userID s return } - if !canCreateBadge(user, p.badgeAdminUserID, t) { + if !canCreateBadge(user, p.badgeAdminUserIDs, t) { p.writeAPIError(w, &APIErrorResponse{ ID: "no_permission", Message: "No permission to create badge of this type", StatusCode: http.StatusForbidden, }) @@ -281,7 +281,7 @@ func (p *Plugin) apiCreateType(w http.ResponseWriter, r *http.Request, userID st return } - if !canCreateType(user, p.badgeAdminUserID, false) { + if !canCreateType(user, p.badgeAdminUserIDs, false) { p.writeAPIError(w, &APIErrorResponse{ ID: "no_permission", Message: "No permission to create type", StatusCode: http.StatusForbidden, }) @@ -350,7 +350,7 @@ func (p *Plugin) apiUpdateBadge(w http.ResponseWriter, r *http.Request, userID s return } - if !canEditBadge(user, p.badgeAdminUserID, badge) { + if !canEditBadge(user, p.badgeAdminUserIDs, badge) { p.writeAPIError(w, &APIErrorResponse{ ID: "no_permission", Message: "No permission to edit this badge", StatusCode: http.StatusForbidden, }) @@ -420,7 +420,7 @@ func (p *Plugin) apiDeleteBadge(w http.ResponseWriter, r *http.Request, userID s return } - if !canEditBadge(user, p.badgeAdminUserID, badge) { + if !canEditBadge(user, p.badgeAdminUserIDs, badge) { p.writeAPIError(w, &APIErrorResponse{ ID: "no_permission", Message: "No permission to delete this badge", StatusCode: http.StatusForbidden, }) @@ -470,7 +470,7 @@ func (p *Plugin) apiDeleteType(w http.ResponseWriter, r *http.Request, userID st return } - if !canEditType(user, p.badgeAdminUserID, t) { + if !canEditType(user, p.badgeAdminUserIDs, t) { p.writeAPIError(w, &APIErrorResponse{ ID: "no_permission", Message: "No permission to delete this type", StatusCode: http.StatusForbidden, }) @@ -550,7 +550,7 @@ func (p *Plugin) dialogCreateBadge(w http.ResponseWriter, r *http.Request, userI return } - if !canCreateBadge(user, p.badgeAdminUserID, t) { + if !canCreateBadge(user, p.badgeAdminUserIDs, t) { dialogError(w, T("badges.api.no_permissions_create_badge", "У вас нет прав на создание этого значка"), nil) return } @@ -586,7 +586,7 @@ func (p *Plugin) dialogCreateType(w http.ResponseWriter, r *http.Request, userID } T := p.getT(u.Locale) - if !canCreateType(u, p.badgeAdminUserID, false) { + if !canCreateType(u, p.badgeAdminUserIDs, false) { dialogError(w, T("badges.api.no_permissions_create_type", "У вас нет прав на создание типа"), nil) return } @@ -684,7 +684,7 @@ func (p *Plugin) dialogSelectType(w http.ResponseWriter, r *http.Request, userID } T := p.getT(u.Locale) - if !canEditType(u, p.badgeAdminUserID, t) { + if !canEditType(u, p.badgeAdminUserIDs, t) { dialogError(w, T("badges.api.cannot_edit_type", "Вы не можете редактировать этот тип"), nil) return } @@ -723,7 +723,7 @@ func (p *Plugin) dialogEditType(w http.ResponseWriter, r *http.Request, userID s return } - if !canEditType(u, p.badgeAdminUserID, originalType) { + if !canEditType(u, p.badgeAdminUserIDs, originalType) { dialogError(w, T("badges.api.no_permissions_edit_type", "У вас нет прав на редактирование этого типа"), nil) return } @@ -828,7 +828,7 @@ func (p *Plugin) dialogSelectBadge(w http.ResponseWriter, r *http.Request, userI } T := p.getT(u.Locale) - if !canEditBadge(u, p.badgeAdminUserID, b) { + if !canEditBadge(u, p.badgeAdminUserIDs, b) { dialogError(w, T("badges.api.cannot_edit_badge", "Вы не можете редактировать этот значок"), nil) return } @@ -867,7 +867,7 @@ func (p *Plugin) dialogEditBadge(w http.ResponseWriter, r *http.Request, userID return } - if !canEditBadge(u, p.badgeAdminUserID, originalBadge) { + if !canEditBadge(u, p.badgeAdminUserIDs, originalBadge) { dialogError(w, T("badges.api.no_permissions_edit_badge", "У вас нет прав на редактирование этого значка"), nil) return } @@ -970,7 +970,7 @@ func (p *Plugin) dialogGrant(w http.ResponseWriter, r *http.Request, userID stri return } - if !canGrantBadge(granter, p.badgeAdminUserID, badge, badgeType) { + if !canGrantBadge(granter, p.badgeAdminUserIDs, badge, badgeType) { dialogError(w, T("badges.api.no_permissions_grant", "У вас нет прав на выдачу этого значка"), nil) return } @@ -1030,7 +1030,7 @@ func (p *Plugin) dialogCreateSubscription(w http.ResponseWriter, r *http.Request } T := p.getT(u.Locale) - if !canCreateSubscription(u, p.badgeAdminUserID, req.ChannelId) { + if !canCreateSubscription(u, p.badgeAdminUserIDs, req.ChannelId) { dialogError(w, T("badges.api.cannot_create_subscription", "Вы не можете создать подписку"), nil) return } @@ -1070,7 +1070,7 @@ func (p *Plugin) dialogDeleteSubscription(w http.ResponseWriter, r *http.Request } T := p.getT(u.Locale) - if !canCreateSubscription(u, p.badgeAdminUserID, req.ChannelId) { + if !canCreateSubscription(u, p.badgeAdminUserIDs, req.ChannelId) { dialogError(w, T("badges.api.cannot_delete_subscription", "Вы не можете удалить подписку"), nil) return } @@ -1162,7 +1162,7 @@ func (p *Plugin) grantBadge(w http.ResponseWriter, r *http.Request, pluginID str return } - if !canGrantBadge(granter, p.badgeAdminUserID, badge, badgeType) { + if !canGrantBadge(granter, p.badgeAdminUserIDs, badge, badgeType) { p.writeAPIError(w, &APIErrorResponse{ ID: "cannot grant badge", Message: "you have no permissions to grant this badge", diff --git a/server/command.go b/server/command.go index ce671d6..8be33ce 100644 --- a/server/command.go +++ b/server/command.go @@ -271,7 +271,7 @@ func (p *Plugin) runEditBadge(args []string, extra *model.CommandArgs) (bool, *m return commandError(err.Error()) } - if !canEditBadge(u, p.badgeAdminUserID, badge) { + if !canEditBadge(u, p.badgeAdminUserIDs, badge) { return commandError(T("badges.error.cannot_edit_badge", "У вас нет прав на редактирование этого значка")) } @@ -359,7 +359,7 @@ func (p *Plugin) runEditType(args []string, extra *model.CommandArgs) (bool, *mo } T := p.getT(u.Locale) - if !canCreateType(u, p.badgeAdminUserID, false) { + if !canCreateType(u, p.badgeAdminUserIDs, false) { return commandError(T("badges.error.no_permissions_edit_type", "У вас нет прав на редактирование типа значков.")) } @@ -379,7 +379,7 @@ func (p *Plugin) runEditType(args []string, extra *model.CommandArgs) (bool, *mo return commandError(err.Error()) } - if !canEditType(u, p.badgeAdminUserID, typeDefinition) { + if !canEditType(u, p.badgeAdminUserIDs, typeDefinition) { return commandError(T("badges.error.cannot_edit_type", "У вас нет прав на редактирование этого типа")) } @@ -493,7 +493,7 @@ func (p *Plugin) runCreateType(args []string, extra *model.CommandArgs) (bool, * } T := p.getT(u.Locale) - if !canCreateType(u, p.badgeAdminUserID, false) { + if !canCreateType(u, p.badgeAdminUserIDs, false) { return commandError(T("badges.error.no_permissions_create_type", "У вас нет прав на создание типа значков.")) } @@ -582,7 +582,7 @@ func (p *Plugin) runGrant(args []string, extra *model.CommandArgs) (bool, *model return commandError(err.Error()) } - if !canGrantBadge(granter, p.badgeAdminUserID, badge, badgeType) { + if !canGrantBadge(granter, p.badgeAdminUserIDs, badge, badgeType) { return commandError(T("badges.error.no_permissions_grant", "У вас нет прав на выдачу этого значка")) } @@ -755,7 +755,7 @@ func (p *Plugin) runCreateSubscription(args []string, extra *model.CommandArgs) } T := p.getT(actingUser.Locale) - if !canCreateSubscription(actingUser, p.badgeAdminUserID, extra.ChannelId) { + if !canCreateSubscription(actingUser, p.badgeAdminUserIDs, extra.ChannelId) { return commandError(T("badges.error.cannot_create_subscription", "Вы не можете создавать подписки")) } @@ -818,7 +818,7 @@ func (p *Plugin) runDeleteSubscription(args []string, extra *model.CommandArgs) } T := p.getT(actingUser.Locale) - if !canCreateSubscription(actingUser, p.badgeAdminUserID, extra.ChannelId) { + if !canCreateSubscription(actingUser, p.badgeAdminUserIDs, extra.ChannelId) { return commandError(T("badges.error.cannot_create_subscription", "Вы не можете создавать подписки")) } diff --git a/server/configuration.go b/server/configuration.go index e93001b..5f2486f 100644 --- a/server/configuration.go +++ b/server/configuration.go @@ -2,6 +2,7 @@ package main import ( "reflect" + "strings" "github.com/pkg/errors" ) @@ -78,13 +79,20 @@ func (p *Plugin) OnConfigurationChange() error { return errors.Wrap(err, "failed to load plugin configuration") } - p.badgeAdminUserID = "" + p.badgeAdminUserIDs = make(map[string]bool) if configuration.BadgesAdmin != "" { - u, err := p.API.GetUserByUsername(configuration.BadgesAdmin) - if err != nil { - return errors.Wrap(err, "cannot get badge admin user") + for username := range strings.SplitSeq(configuration.BadgesAdmin, ",") { + username = strings.TrimSpace(username) + if username == "" { + continue + } + u, err := p.API.GetUserByUsername(username) + if err != nil { + p.API.LogWarn("Cannot find badge admin user", "username", username, "error", err.Error()) + continue + } + p.badgeAdminUserIDs[u.Id] = true } - p.badgeAdminUserID = u.Id } p.setConfiguration(configuration) diff --git a/server/plugin.go b/server/plugin.go index 1768e23..cc8c852 100644 --- a/server/plugin.go +++ b/server/plugin.go @@ -28,7 +28,7 @@ type Plugin struct { BotUserID string store Store router *mux.Router - badgeAdminUserID string + badgeAdminUserIDs map[string]bool i18nBundle *i18n.Bundle } diff --git a/server/suggestions.go b/server/suggestions.go index da0c41e..535bccc 100644 --- a/server/suggestions.go +++ b/server/suggestions.go @@ -23,7 +23,7 @@ func (p *Plugin) filterGrantBadges(user *model.User) ([]*badgesmodel.Badge, erro p.mm.Log.Debug("Badge with missing type", "badge", b) continue } - if canGrantBadge(user, p.badgeAdminUserID, b, badgeType) { + if canGrantBadge(user, p.badgeAdminUserIDs, b, badgeType) { out = append(out, b) } } @@ -39,7 +39,7 @@ func (p *Plugin) filterCreateBadgeTypes(user *model.User) (badgesmodel.BadgeType out := badgesmodel.BadgeTypeList{} for _, t := range types { - if canCreateBadge(user, p.badgeAdminUserID, t) { + if canCreateBadge(user, p.badgeAdminUserIDs, t) { out = append(out, t) } } @@ -55,7 +55,7 @@ func (p *Plugin) filterEditTypes(user *model.User) (badgesmodel.BadgeTypeList, e out := badgesmodel.BadgeTypeList{} for _, t := range types { - if canEditType(user, p.badgeAdminUserID, t) { + if canEditType(user, p.badgeAdminUserIDs, t) { out = append(out, t) } } @@ -71,7 +71,7 @@ func (p *Plugin) filterEditBadges(user *model.User) ([]*badgesmodel.Badge, error out := []*badgesmodel.Badge{} for _, b := range bb { - if canEditBadge(user, p.badgeAdminUserID, b) { + if canEditBadge(user, p.badgeAdminUserIDs, b) { out = append(out, b) } } diff --git a/server/utils.go b/server/utils.go index 49ae72e..345e7cd 100644 --- a/server/utils.go +++ b/server/utils.go @@ -23,8 +23,8 @@ func areRolesAllowed(userRoles []string, allowedRoles map[string]bool) bool { return false } -func canGrantBadge(user *model.User, badgeAdminID string, badge *badgesmodel.Badge, badgeType *badgesmodel.BadgeTypeDefinition) bool { - if badgeAdminID != "" && user.Id == badgeAdminID { +func canGrantBadge(user *model.User, badgeAdminIDs map[string]bool, badge *badgesmodel.Badge, badgeType *badgesmodel.BadgeTypeDefinition) bool { + if badgeAdminIDs[user.Id] { return true } @@ -57,8 +57,8 @@ func canGrantBadge(user *model.User, badgeAdminID string, badge *badgesmodel.Bad return badgeType.CanGrant.Everyone } -func canCreateBadge(user *model.User, badgeAdminID string, badgeType *badgesmodel.BadgeTypeDefinition) bool { - if badgeAdminID != "" && user.Id == badgeAdminID { +func canCreateBadge(user *model.User, badgeAdminIDs map[string]bool, badgeType *badgesmodel.BadgeTypeDefinition) bool { + if badgeAdminIDs[user.Id] { return true } @@ -87,36 +87,36 @@ func canCreateBadge(user *model.User, badgeAdminID string, badgeType *badgesmode return badgeType.CanCreate.Everyone } -func canEditType(user *model.User, badgeAdminID string, badgeType *badgesmodel.BadgeTypeDefinition) bool { - if badgeAdminID != "" && user.Id == badgeAdminID { +func canEditType(user *model.User, badgeAdminIDs map[string]bool, badgeType *badgesmodel.BadgeTypeDefinition) bool { + if badgeAdminIDs[user.Id] { return true } return user.IsSystemAdmin() } -func canEditBadge(user *model.User, badgeAdminID string, badge *badgesmodel.Badge) bool { - if badgeAdminID != "" && user.Id == badgeAdminID { +func canEditBadge(user *model.User, badgeAdminIDs map[string]bool, badge *badgesmodel.Badge) bool { + if badgeAdminIDs[user.Id] { return true } return user.IsSystemAdmin() || user.Id == badge.CreatedBy } -func canCreateType(user *model.User, badgeAdminID string, isPlugin bool) bool { +func canCreateType(user *model.User, badgeAdminIDs map[string]bool, isPlugin bool) bool { if isPlugin { return true } - if badgeAdminID != "" && user.Id == badgeAdminID { + if badgeAdminIDs[user.Id] { return true } return user.IsSystemAdmin() } -func canCreateSubscription(user *model.User, badgeAdminID string, channelID string) bool { - if badgeAdminID != "" && user.Id == badgeAdminID { +func canCreateSubscription(user *model.User, badgeAdminIDs map[string]bool, channelID string) bool { + if badgeAdminIDs[user.Id] { return true }