78 lines
2.0 KiB
Go
78 lines
2.0 KiB
Go
package permissions
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
)
|
|
|
|
// ComputeChannelPermissions returns effective permissions for a user in a specific channel,
|
|
// layering channel overrides on top of server-wide role permissions.
|
|
func (c *Checker) ComputeChannelPermissions(ctx context.Context, serverID, channelID, userID string) (int64, error) {
|
|
base, err := c.GetUserPermissions(ctx, serverID, userID)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if Has(base, ADMINISTRATOR) {
|
|
return base, nil
|
|
}
|
|
|
|
// Everyone role override applies first.
|
|
var everyoneID string
|
|
_ = c.db.QueryRowContext(ctx, `SELECT id FROM roles WHERE server_id = $1 AND is_default = TRUE LIMIT 1`, serverID).Scan(&everyoneID)
|
|
if everyoneID != "" {
|
|
allow, deny, err := c.getOverride(ctx, channelID, "role", everyoneID)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
base |= allow
|
|
base &^= deny
|
|
}
|
|
|
|
// Member-specific role overrides.
|
|
rows, err := c.db.QueryContext(ctx, `
|
|
SELECT r.id FROM roles r
|
|
INNER JOIN member_roles mr ON mr.role_id = r.id
|
|
WHERE mr.user_id = $1 AND mr.server_id = $2
|
|
`, userID, serverID)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
defer rows.Close()
|
|
for rows.Next() {
|
|
var roleID string
|
|
if err := rows.Scan(&roleID); err != nil {
|
|
return 0, err
|
|
}
|
|
allow, deny, err := c.getOverride(ctx, channelID, "role", roleID)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
base |= allow
|
|
base &^= deny
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
// User-specific override wins last.
|
|
allow, deny, err := c.getOverride(ctx, channelID, "user", userID)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
base |= allow
|
|
base &^= deny
|
|
|
|
return base, nil
|
|
}
|
|
|
|
func (c *Checker) getOverride(ctx context.Context, channelID, targetType, targetID string) (allow, deny int64, err error) {
|
|
err = c.db.QueryRowContext(ctx, `
|
|
SELECT allow_bitflags, deny_bitflags FROM channel_overrides
|
|
WHERE channel_id = $1 AND target_type = $2 AND target_id = $3
|
|
`, channelID, targetType, targetID).Scan(&allow, &deny)
|
|
if err == sql.ErrNoRows {
|
|
return 0, 0, nil
|
|
}
|
|
return allow, deny, err
|
|
}
|