Introduce Reservation

This commit is contained in:
binwiederhier 2023-01-02 20:08:37 -05:00
parent 1256ba0429
commit 1733323132
11 changed files with 194 additions and 109 deletions

View file

@ -92,7 +92,7 @@ const (
SELECT read, write
FROM user_access a
JOIN user u ON u.id = a.user_id
WHERE (u.user = '*' OR u.user = ?) AND ? LIKE a.topic
WHERE (u.user = ? OR u.user = ?) AND ? LIKE a.topic
ORDER BY u.user DESC
`
)
@ -123,11 +123,19 @@ const (
DO UPDATE SET read=excluded.read, write=excluded.write, owner_user_id=excluded.owner_user_id
`
selectUserAccessQuery = `
SELECT topic, read, write, IIF(owner_user_id IS NOT NULL AND user_id = owner_user_id,1,0) AS owner
SELECT topic, read, write
FROM user_access
WHERE user_id = (SELECT id FROM user WHERE user = ?)
ORDER BY write DESC, read DESC, topic
`
selectUserReservationsQuery = `
SELECT a_user.topic, a_user.read, a_user.write, a_everyone.read AS everyone_read, a_everyone.write AS everyone_write
FROM user_access a_user
LEFT JOIN user_access a_everyone ON a_user.topic = a_everyone.topic AND a_everyone.user_id = (SELECT id FROM user WHERE user = ?)
WHERE a_user.user_id = a_user.owner_user_id
AND a_user.owner_user_id = (SELECT id FROM user WHERE user = ?)
ORDER BY a_user.topic
`
selectOtherAccessCountQuery = `
SELECT count(*)
FROM user_access
@ -354,7 +362,7 @@ func (a *Manager) Authorize(user *User, topic string, perm Permission) error {
}
// Select the read/write permissions for this user/topic combo. The query may return two
// rows (one for everyone, and one for the user), but prioritizes the user.
rows, err := a.db.Query(selectTopicPermsQuery, username, topic)
rows, err := a.db.Query(selectTopicPermsQuery, Everyone, username, topic)
if err != nil {
return err
}
@ -479,15 +487,10 @@ func (a *Manager) readUser(rows *sql.Rows) (*User, error) {
} else if err := rows.Err(); err != nil {
return nil, err
}
grants, err := a.readGrants(username)
if err != nil {
return nil, err
}
user := &User{
Name: username,
Hash: hash,
Role: Role(role),
Grants: grants,
Name: username,
Hash: hash,
Role: Role(role),
Stats: &Stats{
Messages: messages,
Emails: emails,
@ -513,7 +516,8 @@ func (a *Manager) readUser(rows *sql.Rows) (*User, error) {
return user, nil
}
func (a *Manager) readGrants(username string) ([]Grant, error) {
// Grants returns all user-specific access control entries
func (a *Manager) Grants(username string) ([]Grant, error) {
rows, err := a.db.Query(selectUserAccessQuery, username)
if err != nil {
return nil, err
@ -522,8 +526,8 @@ func (a *Manager) readGrants(username string) ([]Grant, error) {
grants := make([]Grant, 0)
for rows.Next() {
var topic string
var read, write, owner bool
if err := rows.Scan(&topic, &read, &write, &owner); err != nil {
var read, write bool
if err := rows.Scan(&topic, &read, &write); err != nil {
return nil, err
} else if err := rows.Err(); err != nil {
return nil, err
@ -532,12 +536,39 @@ func (a *Manager) readGrants(username string) ([]Grant, error) {
TopicPattern: fromSQLWildcard(topic),
AllowRead: read,
AllowWrite: write,
Owner: owner,
})
}
return grants, nil
}
// Reservations returns all user-owned topics, and the associated everyone-access
func (a *Manager) Reservations(username string) ([]Reservation, error) {
rows, err := a.db.Query(selectUserReservationsQuery, Everyone, username)
if err != nil {
return nil, err
}
defer rows.Close()
reservations := make([]Reservation, 0)
for rows.Next() {
var topic string
var read, write bool
var everyoneRead, everyoneWrite sql.NullBool
if err := rows.Scan(&topic, &read, &write, &everyoneRead, &everyoneWrite); err != nil {
return nil, err
} else if err := rows.Err(); err != nil {
return nil, err
}
reservations = append(reservations, Reservation{
TopicPattern: topic,
AllowRead: read,
AllowWrite: write,
AllowEveryoneRead: everyoneRead.Bool, // false if null
AllowEveryoneWrite: everyoneWrite.Bool, // false if null
})
}
return reservations, nil
}
// ChangePassword changes a user's password
func (a *Manager) ChangePassword(username, password string) error {
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcryptCost)