<commit_before>package user

import (
	"context"
	"errors"
	"fmt"
	"net/http"

	"github.com/gempir/gempbot/pkg/api"
	"github.com/gempir/gempbot/pkg/chat"
	"github.com/gempir/gempbot/pkg/config"
	"github.com/gempir/gempbot/pkg/helixclient"
	"github.com/gempir/gempbot/pkg/log"
	"github.com/gempir/gempbot/pkg/slice"
	"github.com/gempir/gempbot/pkg/store"
)

type UserAdmin struct {
	cfg         *config.Config
	db          *store.Database
	helixClient *helixclient.Client
	chatClient  *chat.ChatClient
}

func NewUserAdmin(cfg *config.Config, db *store.Database, helixClient *helixclient.Client, chatClient *chat.ChatClient) *UserAdmin {
	return &UserAdmin{cfg, db, helixClient, chatClient}
}

type UserConfig struct {
	Permissions map[string]Permission
	Protected   Protected
}

func (u *UserConfig) isEditor(userID string) bool {
	val, ok := u.Permissions[userID]

	return ok && val.Editor
}

func (u *UserConfig) isEditorFor(userID string) bool {
	return slice.Contains(u.Protected.EditorFor, userID)
}

type Protected struct {
	EditorFor     []string
	CurrentUserID string
}

type Permission struct {
	Editor     bool
	Prediction bool
}

func createDefaultUserConfig() UserConfig {
	return UserConfig{
		Permissions: map[string]Permission{},
		Protected: Protected{
			EditorFor:     []string{},
			CurrentUserID: "",
		},
	}
}

func (u *UserAdmin) GetUserConfig(userID string) UserConfig {
	uCfg := createDefaultUserConfig()

	uCfg.Protected.CurrentUserID = userID

	perms := u.db.GetChannelPermissions(userID)
	for _, perm := range perms {
		uCfg.Permissions[perm.TwitchID] = Permission{perm.Editor, perm.Prediction}
	}

	for _, perm := range u.db.GetUserPermissions(userID) {
		uCfg.Protected.EditorFor = append(uCfg.Protected.EditorFor, perm.ChannelTwitchId)
	}

	return uCfg
}

func (u *UserAdmin) ConvertUserConfig(uCfg UserConfig, toNames bool) (UserConfig, api.Error) {
	all := map[string]string{}

	for _, user := range uCfg.Protected.EditorFor {
		all[user] = user
	}

	for user := range uCfg.Permissions {
		all[user] = user
	}

	allSlice := slice.MapToSlice(all)

	var err error
	var userData map[string]helixclient.UserData
	if toNames {
		userData, err = u.helixClient.GetUsersByUserIds(allSlice)
	} else {
		userData, err = u.helixClient.GetUsersByUsernames(allSlice)
	}
	if err != nil || len(userData) != len(all) {
		log.Errorf("Failed to get users %s", err)
		return UserConfig{}, api.NewApiError(http.StatusBadRequest, errors.New("failed to get users"))
	}

	editorFor := []string{}
	for _, editor := range uCfg.Protected.EditorFor {
		data, ok := userData[editor]
		if !ok {
			continue
		}

		if toNames {
			editorFor = append(editorFor, data.Login)
		} else {
			editorFor = append(editorFor, data.ID)
		}
	}
	uCfg.Protected.EditorFor = editorFor

	perms := map[string]Permission{}
	for user, perm := range uCfg.Permissions {
		data, ok := userData[user]
		if !ok {
			continue
		}

		var newUser string

		if toNames {
			newUser = data.Login
		} else {<commit_msg>make ui resilient against banned users<commit_after>package user

import (
	"context"
	"fmt"
	"net/http"

	"github.com/gempir/gempbot/pkg/api"
	"github.com/gempir/gempbot/pkg/chat"
	"github.com/gempir/gempbot/pkg/config"
	"github.com/gempir/gempbot/pkg/helixclient"
	"github.com/gempir/gempbot/pkg/log"
	"github.com/gempir/gempbot/pkg/slice"
	"github.com/gempir/gempbot/pkg/store"
)

type UserAdmin struct {
	cfg         *config.Config
	db          *store.Database
	helixClient *helixclient.Client
	chatClient  *chat.ChatClient
}

func NewUserAdmin(cfg *config.Config, db *store.Database, helixClient *helixclient.Client, chatClient *chat.ChatClient) *UserAdmin {
	return &UserAdmin{cfg, db, helixClient, chatClient}
}

type UserConfig struct {
	Permissions map[string]Permission
	Protected   Protected
}

func (u *UserConfig) isEditor(userID string) bool {
	val, ok := u.Permissions[userID]

	return ok && val.Editor
}

func (u *UserConfig) isEditorFor(userID string) bool {
	return slice.Contains(u.Protected.EditorFor, userID)
}

type Protected struct {
	EditorFor     []string
	CurrentUserID string
}

type Permission struct {
	Editor     bool
	Prediction bool
}

func createDefaultUserConfig() UserConfig {
	return UserConfig{
		Permissions: map[string]Permission{},
		Protected: Protected{
			EditorFor:     []string{},
			CurrentUserID: "",
		},
	}
}

func (u *UserAdmin) GetUserConfig(userID string) UserConfig {
	uCfg := createDefaultUserConfig()

	uCfg.Protected.CurrentUserID = userID

	perms := u.db.GetChannelPermissions(userID)
	for _, perm := range perms {
		uCfg.Permissions[perm.TwitchID] = Permission{perm.Editor, perm.Prediction}
	}

	for _, perm := range u.db.GetUserPermissions(userID) {
		uCfg.Protected.EditorFor = append(uCfg.Protected.EditorFor, perm.ChannelTwitchId)
	}

	return uCfg
}

func (u *UserAdmin) ConvertUserConfig(uCfg UserConfig, toNames bool) (UserConfig, api.Error) {
	all := map[string]string{}

	for _, user := range uCfg.Protected.EditorFor {
		all[user] = user
	}

	for user := range uCfg.Permissions {
		all[user] = user
	}

	allSlice := slice.MapToSlice(all)

	var err error
	var userData map[string]helixclient.UserData
	if toNames {
		userData, err = u.helixClient.GetUsersByUserIds(allSlice)
	} else {
		userData, err = u.helixClient.GetUsersByUsernames(allSlice)
	}
	if err != nil || len(userData) != len(all) {
		log.Errorf("Failed to get all users, some might be banned. %s", err)
	}

	editorFor := []string{}
	for _, editor := range uCfg.Protected.EditorFor {
		data, ok := userData[editor]
		if !ok {
			continue
		}

		if toNames {
			editorFor = append(editorFor, data.Login)
		} else {
			editorFor = append(editorFor, data.ID)
		}
	}
	uCfg.Protected.EditorFor = editorFor

	perms := map[string]Permission{}
	for user, perm := range uCfg.Permissions {
		data, ok := userData[user]
		if !ok {
			continue
		}

		var newUser string

		if toNames {
			newUser = data.Login
		} else {
{'fraction_non_alphanumeric': 0.12126834204756283, 'fraction_numerical': 0.0, 'mean_word_length': 4.174520069808028, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4771081', 'n_tokens_mistral': 2210, 'n_tokens_neox': 2100, 'n_words': 450}