package permissions import ( "context" "fmt" ) // Channel вычисляет права пользователя в конкретной комнате: базовые права // сервера, затем оверрайды ролей, затем оверрайд пользователя (AGENT.md 6.2). func (c *Calculator) Channel(ctx context.Context, guildID, channelID, userID uint64, instanceAdmin bool) (Resolved, error) { if cached, ok := c.cache.GetChannel(channelID, userID); ok { cached.IsInstanceAdmin = instanceAdmin return cached, nil } resolved, err := c.Guild(ctx, guildID, userID, instanceAdmin) if err != nil { return Resolved{}, err } resolved.Channel = resolved.Guild if !resolved.IsMember && !resolved.IsInstanceAdmin { // Не участник не видит ничего, даже если есть персональный оверрайд. c.cache.PutChannel(channelID, userID, resolved) return resolved, nil } if resolved.IsInstanceAdmin || resolved.Guild.Has(Administrator) { c.cache.PutChannel(channelID, userID, resolved) return resolved, nil } overrides, err := c.source.ChannelOverrides(ctx, channelID) if err != nil { return Resolved{}, fmt.Errorf("load channel overrides: %w", err) } roles, err := c.source.GuildRoles(ctx, guildID) if err != nil { return Resolved{}, fmt.Errorf("load guild roles: %w", err) } memberRoleIDs, err := c.source.MemberRoleIDs(ctx, guildID, userID) if err != nil { return Resolved{}, fmt.Errorf("load member roles: %w", err) } assigned := make(map[uint64]bool, len(memberRoleIDs)+1) for _, roleID := range memberRoleIDs { assigned[roleID] = true } defaultRoleID := uint64(0) for _, role := range roles { if role.IsDefault { defaultRoleID = role.ID assigned[role.ID] = true break } } // Порядок как в AGENT.md 6.2: базовые права роли @user → оверрайды ролей → // персональный оверрайд пользователя. denied, allowed := Permission(0), Permission(0) for _, override := range overrides { if override.TargetType != "role" { continue } if override.TargetID == defaultRoleID || assigned[override.TargetID] { denied |= override.Deny allowed |= override.Allow } } computed := (resolved.Guild &^ denied) | allowed // Персональный deny обязан перебить ролевой allow, поэтому применяется // к уже вычисленному результату. var userDeny, userAllow Permission for _, override := range overrides { if override.TargetType == "user" && override.TargetID == userID { userDeny |= override.Deny userAllow |= override.Allow } } resolved.Channel = (computed &^ userDeny) | userAllow c.cache.PutChannel(channelID, userID, resolved) return resolved, nil }