feat: add Winter user groups

- user_groups (seeded with the guest and registered groups) and the
  users_groups pivot, folded from the PHP v1.1.1 and v2.8.0 migrations
  into migration 202610020001_create_user_groups
- models.UserGroup and a User.Groups relation that is never serialized
- classes.UserGroupCodes and classes.HasGroupCode for server-side checks
  such as the site-admin group code admin
- additive only: no route, payload or existing column changes; the user
  payload still answers "groups":[]
This commit is contained in:
Jakub Zych
2026-10-02 11:44:01 +02:00
parent c65ab3cdac
commit 86970074b7
8 changed files with 301 additions and 13 deletions

47
classes/user_groups.go Normal file
View File

@@ -0,0 +1,47 @@
package classes
import (
"context"
"fmt"
"gorm.io/gorm"
)
// UserGroupCodes returns the codes of the user's groups ordered by
// user_groups.id; groups without a code are skipped. A user in no group
// gets an empty slice.
func UserGroupCodes(ctx context.Context, db *gorm.DB, userID uint) ([]string, error) {
if db == nil {
return nil, fmt.Errorf("golem15.user: gorm handle is missing")
}
codes := []string{}
err := db.WithContext(ctx).
Table("user_groups").
Joins("JOIN users_groups ON users_groups.user_group_id = user_groups.id").
Where("users_groups.user_id = ? AND user_groups.code IS NOT NULL", userID).
Order("user_groups.id").
Pluck("user_groups.code", &codes).Error
if err != nil {
return nil, err
}
return codes, nil
}
// HasGroupCode reports whether the user belongs to a group with code, the
// PHP `$user->groups->pluck('code')->contains($code)` check (for example
// the site-admin group code admin).
func HasGroupCode(ctx context.Context, db *gorm.DB, userID uint, code string) (bool, error) {
if db == nil {
return false, fmt.Errorf("golem15.user: gorm handle is missing")
}
var n int64
err := db.WithContext(ctx).
Table("user_groups").
Joins("JOIN users_groups ON users_groups.user_group_id = user_groups.id").
Where("users_groups.user_id = ? AND user_groups.code = ?", userID, code).
Count(&n).Error
if err != nil {
return false, err
}
return n > 0, nil
}