Initial commit: JustAMessenger v0.1.0

Серверная часть (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 — спецификация протокола
This commit is contained in:
SashegDev
2026-06-06 22:39:14 +00:00
commit 096c4d0a2d
40 changed files with 5054 additions and 0 deletions
+180
View File
@@ -0,0 +1,180 @@
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
}