096c4d0a2d
Серверная часть (Go): - WebSocket сервер с бинарным протоколом - XChaCha20-Poly1305 шифрование - zstd сжатие с дедупликацией (64KB чанки) - SQLite хранилище (WAL режим) - Управление гильдиями, каналами, ролями - Федерация между серверами (ed25519) - REST API + WebSocket endpoints Клиентская часть (Flutter): - Material Design 3 тёмная тема (Discord-like) - WebSocket соединение с сервером - Экраны: сплэш, логин, домашний, гильдии, чат - Модели: пользователи, гильдии, каналы, сообщения, роли - Сервисы: соединение, API, криптография, тема - Виджеты: иконки гильдий, сообщения, ввод чата - Web сборка (PWA) Документация: - AGENTS.md — контекст для ИИ ассистентов - docs/protocol.md — спецификация протокола
181 lines
4.3 KiB
Go
181 lines
4.3 KiB
Go
package role
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/justamessenger/server/internal/database"
|
|
"github.com/justamessenger/server/internal/models"
|
|
)
|
|
|
|
type Manager struct {
|
|
db *database.DB
|
|
}
|
|
|
|
func NewManager(db *database.DB) *Manager {
|
|
return &Manager{db: db}
|
|
}
|
|
|
|
var DefaultPermissions = []string{
|
|
"view_channels",
|
|
"send_messages",
|
|
"add_reactions",
|
|
"read_message_history",
|
|
"connect_voice",
|
|
"speak",
|
|
}
|
|
|
|
var AdminPermissions = []string{
|
|
"administrator",
|
|
"manage_guild",
|
|
"manage_channels",
|
|
"manage_roles",
|
|
"manage_messages",
|
|
"kick_members",
|
|
"ban_members",
|
|
"view_channels",
|
|
"send_messages",
|
|
"add_reactions",
|
|
"read_message_history",
|
|
"connect_voice",
|
|
"speak",
|
|
"mute_members",
|
|
"deafen_members",
|
|
"move_members",
|
|
"stream",
|
|
}
|
|
|
|
func (m *Manager) CreateDefaultRoles(guildID string) error {
|
|
_, err := m.db.Exec(
|
|
`INSERT OR IGNORE INTO roles (id, guild_id, name, color, position, permissions, is_default)
|
|
VALUES (?, ?, 'everyone', 0, 0, ?, 1)`,
|
|
uuid.New().String(), guildID, mustJSON(DefaultPermissions),
|
|
)
|
|
return err
|
|
}
|
|
|
|
func mustJSON(v interface{}) string {
|
|
b, _ := json.Marshal(v)
|
|
return string(b)
|
|
}
|
|
|
|
func (m *Manager) Create(guildID, name string, color, position int, permissions []string) (*models.Role, error) {
|
|
id := uuid.New().String()
|
|
permJSON, _ := json.Marshal(permissions)
|
|
_, err := m.db.Exec(
|
|
`INSERT INTO roles (id, guild_id, name, color, position, permissions)
|
|
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
id, guildID, name, color, position, string(permJSON),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return m.Get(id)
|
|
}
|
|
|
|
func (m *Manager) Get(id string) (*models.Role, error) {
|
|
row := m.db.QueryRow(
|
|
`SELECT id, guild_id, name, color, position, permissions, is_default
|
|
FROM roles WHERE id = ?`, id,
|
|
)
|
|
r := &models.Role{}
|
|
var permJSON string
|
|
err := row.Scan(&r.ID, &r.GuildID, &r.Name, &r.Color, &r.Position, &permJSON, &r.IsDefault)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
json.Unmarshal([]byte(permJSON), &r.Permissions)
|
|
return r, nil
|
|
}
|
|
|
|
func (m *Manager) ListByGuild(guildID string) ([]*models.Role, error) {
|
|
rows, err := m.db.Query(
|
|
`SELECT id, guild_id, name, color, position, permissions, is_default
|
|
FROM roles WHERE guild_id = ? ORDER BY position DESC`, guildID,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var roles []*models.Role
|
|
for rows.Next() {
|
|
r := &models.Role{}
|
|
var permJSON string
|
|
if err := rows.Scan(&r.ID, &r.GuildID, &r.Name, &r.Color, &r.Position, &permJSON, &r.IsDefault); err != nil {
|
|
return nil, err
|
|
}
|
|
json.Unmarshal([]byte(permJSON), &r.Permissions)
|
|
roles = append(roles, r)
|
|
}
|
|
return roles, nil
|
|
}
|
|
|
|
func (m *Manager) AssignRole(roleID, userID string) error {
|
|
_, err := m.db.Exec(
|
|
`INSERT OR IGNORE INTO role_members (role_id, user_id) VALUES (?, ?)`,
|
|
roleID, userID,
|
|
)
|
|
return err
|
|
}
|
|
|
|
func (m *Manager) RemoveRole(roleID, userID string) error {
|
|
result, err := m.db.Exec(
|
|
`DELETE FROM role_members WHERE role_id = ? AND user_id = ?`,
|
|
roleID, userID,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
affected, _ := result.RowsAffected()
|
|
if affected == 0 {
|
|
return errors.New("role assignment not found")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (m *Manager) GetUserRoles(guildID, userID string) ([]*models.Role, error) {
|
|
rows, err := m.db.Query(
|
|
`SELECT r.id, r.guild_id, r.name, r.color, r.position, r.permissions, r.is_default
|
|
FROM roles r
|
|
INNER JOIN role_members rm ON r.id = rm.role_id
|
|
WHERE r.guild_id = ? AND rm.user_id = ?
|
|
UNION
|
|
SELECT id, guild_id, name, color, position, permissions, is_default
|
|
FROM roles WHERE guild_id = ? AND is_default = 1
|
|
ORDER BY position DESC`, guildID, userID, guildID,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var roles []*models.Role
|
|
for rows.Next() {
|
|
r := &models.Role{}
|
|
var permJSON string
|
|
if err := rows.Scan(&r.ID, &r.GuildID, &r.Name, &r.Color, &r.Position, &permJSON, &r.IsDefault); err != nil {
|
|
return nil, err
|
|
}
|
|
json.Unmarshal([]byte(permJSON), &r.Permissions)
|
|
roles = append(roles, r)
|
|
}
|
|
return roles, nil
|
|
}
|
|
|
|
func (m *Manager) HasPermission(guildID, userID, permission string) (bool, error) {
|
|
roles, err := m.GetUserRoles(guildID, userID)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
for _, r := range roles {
|
|
for _, p := range r.Permissions {
|
|
if p == "administrator" || p == permission {
|
|
return true, nil
|
|
}
|
|
}
|
|
}
|
|
return false, nil
|
|
}
|