Some checks failed
Build and Release / Create Release (push) Has been skipped
Build and Release / Integration Tests (PostgreSQL) (push) Successful in 1m41s
Build and Release / Lint (push) Failing after 2m0s
Build and Release / Build Binaries (amd64, darwin) (push) Has been skipped
Build and Release / Build Binaries (amd64, linux) (push) Has been skipped
Build and Release / Build Binaries (amd64, windows) (push) Has been skipped
Build and Release / Build Binaries (arm64, darwin) (push) Has been skipped
Build and Release / Build Binaries (arm64, linux) (push) Has been skipped
Build and Release / Unit Tests (push) Successful in 2m1s
- Rename OrgOverviewStats fields to match template expectations
- Add TotalStars field to show aggregate star count
- Add CountOrgRepoStars function to repo model
- Fix API struct and handler to use new field names
🤖 Generated with Claude Code
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
171 lines
4.0 KiB
Go
171 lines
4.0 KiB
Go
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package organization
|
|
|
|
import (
|
|
"context"
|
|
|
|
"code.gitea.io/gitea/models/db"
|
|
user_model "code.gitea.io/gitea/models/user"
|
|
)
|
|
|
|
const (
|
|
// ProfileRepoName is the name of the special profile repository
|
|
ProfileRepoName = ".profile"
|
|
// ProfileReadmePath is the path to the profile README
|
|
ProfileReadmePath = "README.md"
|
|
// ProfileAssetsPath is the path to profile assets
|
|
ProfileAssetsPath = "assets/"
|
|
// ProfileStylePath is the path to custom CSS
|
|
ProfileStylePath = "style.css"
|
|
)
|
|
|
|
// PublicMember represents a public member of an organization for display
|
|
type PublicMember struct {
|
|
*user_model.User
|
|
Role string // "Owner", "Admin", "Member"
|
|
}
|
|
|
|
// GetPublicOrgMembers returns public members of an organization
|
|
func GetPublicOrgMembers(ctx context.Context, orgID int64, limit int) ([]*PublicMember, int64, error) {
|
|
// Count total public members
|
|
total, err := db.GetEngine(ctx).
|
|
Where("org_id = ? AND is_public = ?", orgID, true).
|
|
Count(new(OrgUser))
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
// Get public org users
|
|
orgUsers := make([]*OrgUser, 0, limit)
|
|
sess := db.GetEngine(ctx).
|
|
Where("org_id = ? AND is_public = ?", orgID, true)
|
|
if limit > 0 {
|
|
sess = sess.Limit(limit)
|
|
}
|
|
if err := sess.Find(&orgUsers); err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
if len(orgUsers) == 0 {
|
|
return []*PublicMember{}, total, nil
|
|
}
|
|
|
|
// Get user IDs
|
|
userIDs := make([]int64, len(orgUsers))
|
|
for i, ou := range orgUsers {
|
|
userIDs[i] = ou.UID
|
|
}
|
|
|
|
// Load users
|
|
users, err := user_model.GetUsersByIDs(ctx, userIDs)
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
userMap := make(map[int64]*user_model.User)
|
|
for _, u := range users {
|
|
userMap[u.ID] = u
|
|
}
|
|
|
|
// Get owners team to determine roles
|
|
org, err := GetOrgByID(ctx, orgID)
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
ownersTeam, err := org.GetOwnerTeam(ctx)
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
ownerIDs := make(map[int64]bool)
|
|
if ownersTeam != nil {
|
|
if err := ownersTeam.LoadMembers(ctx); err != nil {
|
|
return nil, 0, err
|
|
}
|
|
for _, m := range ownersTeam.Members {
|
|
ownerIDs[m.ID] = true
|
|
}
|
|
}
|
|
|
|
// Build result with roles
|
|
members := make([]*PublicMember, 0, len(orgUsers))
|
|
for _, ou := range orgUsers {
|
|
user := userMap[ou.UID]
|
|
if user == nil {
|
|
continue
|
|
}
|
|
|
|
role := "Member"
|
|
if ownerIDs[ou.UID] {
|
|
role = "Owner"
|
|
} else {
|
|
// Check if admin (has admin access to any team)
|
|
isAdmin, _ := IsOrganizationAdmin(ctx, orgID, ou.UID)
|
|
if isAdmin {
|
|
role = "Admin"
|
|
}
|
|
}
|
|
|
|
members = append(members, &PublicMember{
|
|
User: user,
|
|
Role: role,
|
|
})
|
|
}
|
|
|
|
return members, total, nil
|
|
}
|
|
|
|
// SetMemberPublicVisibility sets the public visibility of a member
|
|
func SetMemberPublicVisibility(ctx context.Context, orgID, userID int64, isPublic bool) error {
|
|
_, err := db.GetEngine(ctx).
|
|
Where("org_id = ? AND uid = ?", orgID, userID).
|
|
Cols("is_public").
|
|
Update(&OrgUser{IsPublic: isPublic})
|
|
return err
|
|
}
|
|
|
|
// GetMemberPublicVisibility gets the public visibility status of a member
|
|
func GetMemberPublicVisibility(ctx context.Context, orgID, userID int64) (bool, error) {
|
|
orgUser := new(OrgUser)
|
|
has, err := db.GetEngine(ctx).
|
|
Where("org_id = ? AND uid = ?", orgID, userID).
|
|
Get(orgUser)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if !has {
|
|
return false, nil
|
|
}
|
|
return orgUser.IsPublic, nil
|
|
}
|
|
|
|
// OrgOverviewStats represents statistics for the organization overview
|
|
type OrgOverviewStats struct {
|
|
TotalRepos int64
|
|
TotalMembers int64
|
|
TotalTeams int64
|
|
TotalStars int64
|
|
}
|
|
|
|
// GetOrgMemberAndTeamCounts returns member and team counts for an organization
|
|
func GetOrgMemberAndTeamCounts(ctx context.Context, orgID int64) (memberCount, teamCount int64, err error) {
|
|
memberCount, err = db.GetEngine(ctx).
|
|
Where("org_id = ?", orgID).
|
|
Count(new(OrgUser))
|
|
if err != nil {
|
|
return 0, 0, err
|
|
}
|
|
|
|
teamCount, err = db.GetEngine(ctx).
|
|
Where("org_id = ?", orgID).
|
|
Count(new(Team))
|
|
if err != nil {
|
|
return 0, 0, err
|
|
}
|
|
|
|
return memberCount, teamCount, nil
|
|
}
|