package lishwist import ( "fmt" "lishwist/core/internal/db" "strconv" "strings" ) type Group struct { Id string Name string Reference string Members []User } func (g *Group) MemberIndex(userId string) int { for i, u := range g.Members { if u.Id == userId { return i } } return -1 } func queryManyGroups(query string, args ...any) ([]Group, error) { groups := []Group{} rows, err := db.Connection.Query(query, args...) if err != nil { return nil, fmt.Errorf("Query failed: %w", err) } defer rows.Close() for rows.Next() { var group Group err := rows.Scan(&group.Id, &group.Name, &group.Reference) if err != nil { return nil, fmt.Errorf("Failed to scan row: %w", err) } members, err := queryManyGroupMembers(group.Id) if err != nil { return nil, fmt.Errorf("Failed to query for group members: %w", err) } group.Members = members groups = append(groups, group) } err = rows.Err() if err != nil { return nil, fmt.Errorf("Rows error: %w", err) } return groups, nil } func queryOneGroup(query string, args ...any) (*Group, error) { groups, err := queryManyGroups(query, args...) if err != nil { return nil, err } if len(groups) < 1 { return nil, nil } return &groups[0], nil } func queryManyGroupMembers(groupId string) ([]User, error) { query := "SELECT user.id, user.name, user.display_name, user.reference, user.is_admin, user.is_live, user.password_from_admin FROM v_user AS user JOIN group_member ON group_member.user_id = user.id JOIN [group] ON [group].id = group_member.group_id WHERE [group].id = ? ORDER BY group_member.user_id" members, err := queryManyUsers(query, groupId) if err != nil { return members, err } return members, nil } func (s *Session) GetGroupByReference(reference string) (*Group, error) { // FIXME: This function doesn't make much sense when there's already a public function to fetch any group, below stmt := "SELECT [group].id, [group].name, [group].reference FROM [group] JOIN group_member ON [group].id == group_member.group_id WHERE [group].reference = ? AND group_member.user_id = ?;" return queryOneGroup(stmt, reference, s.User().Id) } func GetGroupByReference(reference string) (*Group, error) { stmt := "SELECT [group].id, [group].name, [group].reference FROM [group] WHERE [group].reference = ?;" return queryOneGroup(stmt, reference) } func (a *Admin) ListGroups() ([]Group, error) { query := "SELECT id, name, reference FROM [group];" return queryManyGroups(query) } func (a *Admin) CreateGroup(name string, reference string) (*Group, error) { name = strings.TrimSpace(name) reference = strings.TrimSpace(reference) stmt := "INSERT INTO [group] (name, reference) VALUES (?, ?)" result, err := db.Connection.Exec(stmt, name, reference) if err != nil { return nil, err } id, err := result.LastInsertId() if err != nil { return nil, err } group := Group{ Id: strconv.FormatInt(id, 10), Name: name, Reference: reference, } recordEventCreateGroup(a.session.user.Id, group.Id) return &group, nil } func (a *Admin) AddUserToGroup(userId, groupId string) error { stmt := "INSERT INTO group_member (user_id, group_id) VALUES (?, ?)" result, err := db.Connection.Exec(stmt, userId, groupId) if err != nil { return fmt.Errorf("query execution failed: %w", err) } id, err := result.LastInsertId() if err != nil { return fmt.Errorf("failed to get last insert id: %w", err) } recordEventCreateGroupMember(a.session.user.Id, strconv.FormatInt(id, 10)) return nil } func (a *Admin) RemoveUserFromGroup(userId, groupId string) error { stmt := "DELETE FROM group_member WHERE group_id = ? AND user_id = ?" _, err := db.Connection.Exec(stmt, userId, groupId) if err != nil { return err } return nil } // Get the groups the session user belongs to func (u *Session) GetGroups() ([]Group, error) { stmt := "SELECT [group].id, [group].name, [group].reference FROM [group] JOIN group_member ON group_member.group_id = [group].id JOIN v_user AS user ON user.id = group_member.user_id WHERE user.id = ?" return queryManyGroups(stmt, u.User().Id) }