2026-05-26 03:40:01 +08:00

679 lines
24 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package host
import (
"context"
"database/sql"
"fmt"
"strings"
"hyapp/pkg/appcode"
"hyapp/pkg/xerr"
hostdomain "hyapp/services/user-service/internal/domain/host"
hostservice "hyapp/services/user-service/internal/service/host"
)
// SearchAgencies 返回用户当前区域内可加入的有效 Agency。
func (r *Repository) SearchAgencies(ctx context.Context, command hostservice.SearchAgenciesCommand) ([]hostdomain.Agency, error) {
regionID, err := r.userRegion(ctx, r.db, command.UserID, "")
if err != nil {
return nil, err
}
if regionID <= 0 {
// 区域是 Agency 搜索和申请的硬边界,缺失时不能退化成全局搜索。
return nil, xerr.New(xerr.InvalidArgument, "user region is required")
}
query := fmt.Sprintf(`
SELECT %s
FROM agencies
WHERE app_code = ? AND region_id = ? AND status = ? AND join_enabled = TRUE
`, agencyColumns)
args := []any{appcode.FromContext(ctx), regionID, hostdomain.AgencyStatusActive}
if strings.TrimSpace(command.Keyword) != "" {
keyword := strings.TrimSpace(command.Keyword)
query += ` AND (name LIKE ? OR owner_user_id IN (
SELECT user_id
FROM users
WHERE app_code = ? AND current_display_user_id = ?
))`
args = append(args, "%"+keyword+"%", appcode.FromContext(ctx), keyword)
}
query += " ORDER BY created_at_ms DESC, agency_id DESC LIMIT ?"
args = append(args, command.PageSize)
rows, err := r.db.QueryContext(ctx, query, args...)
if err != nil {
return nil, err
}
defer rows.Close()
agencies := make([]hostdomain.Agency, 0, command.PageSize)
for rows.Next() {
agency, err := scanAgency(rows)
if err != nil {
return nil, err
}
agencies = append(agencies, agency)
}
return agencies, rows.Err()
}
// GetHostProfile 读取 Host 身份事实。
func (r *Repository) GetHostProfile(ctx context.Context, userID int64) (hostdomain.HostProfile, error) {
return queryHostProfile(ctx, r.db, "WHERE user_id = ?", userID)
}
// GetBDProfile 读取 BD 身份事实。
func (r *Repository) GetBDProfile(ctx context.Context, userID int64) (hostdomain.BDProfile, error) {
return queryBDProfile(ctx, r.db, "WHERE user_id = ?", userID)
}
// GetCoinSellerProfile 读取币商身份事实。
func (r *Repository) GetCoinSellerProfile(ctx context.Context, userID int64) (hostdomain.CoinSellerProfile, error) {
return queryCoinSellerProfile(ctx, r.db, "WHERE user_id = ?", userID)
}
// ListActiveCoinSellersInMyRegion 返回当前用户所在区域的启用币商列表。
// 该查询从 users.region_id 出发过滤,避免把区域条件交给 gateway 或客户端传入。
func (r *Repository) ListActiveCoinSellersInMyRegion(ctx context.Context, userID int64) ([]hostdomain.CoinSellerListItem, error) {
regionID, err := r.userRegion(ctx, r.db, userID, "")
if err != nil {
return nil, err
}
if regionID <= 0 {
// 币商列表是区域内充值入口,缺少当前区域时不能降级成全局列表。
return nil, xerr.New(xerr.InvalidArgument, "user region is required")
}
if err := requireActiveRegion(ctx, r.db, regionID); err != nil {
return nil, err
}
rows, err := r.db.QueryContext(ctx, `
SELECT
u.user_id,
u.current_display_user_id,
COALESCE(u.username, ''),
COALESCE(u.avatar, ''),
COALESCE(country.country_id, 0),
COALESCE(u.country, ''),
COALESCE(country.country_name, ''),
COALESCE(country.country_display_name, ''),
u.region_id,
COALESCE(region.region_code, ''),
COALESCE(region.name, ''),
seller.status,
seller.merchant_asset_type,
seller.updated_at_ms
FROM users u
INNER JOIN coin_seller_profiles seller
ON seller.app_code = u.app_code AND seller.user_id = u.user_id
LEFT JOIN countries country
ON country.app_code = u.app_code AND country.country_code = u.country
LEFT JOIN regions region
ON region.app_code = u.app_code AND region.region_id = u.region_id
WHERE u.app_code = ?
AND u.region_id = ?
AND u.status = 'active'
AND seller.status = ?
AND seller.merchant_asset_type = ?
ORDER BY seller.updated_at_ms DESC, u.user_id DESC
`, appcode.FromContext(ctx), regionID, hostdomain.CoinSellerStatusActive, hostdomain.CoinSellerMerchantAssetType)
if err != nil {
return nil, err
}
defer rows.Close()
items := make([]hostdomain.CoinSellerListItem, 0)
for rows.Next() {
var item hostdomain.CoinSellerListItem
if err := rows.Scan(
&item.UserID,
&item.DisplayUserID,
&item.Username,
&item.Avatar,
&item.CountryID,
&item.CountryCode,
&item.CountryName,
&item.CountryDisplayName,
&item.RegionID,
&item.RegionCode,
&item.RegionName,
&item.Status,
&item.MerchantAssetType,
&item.UpdatedAtMs,
); err != nil {
return nil, err
}
items = append(items, item)
}
return items, rows.Err()
}
// GetUserRoleSummary 用一组索引点查构造我的页角色摘要。
// 摘要只表达入口显隐需要的当前身份,不加载成员列表、团队统计或薪资数据。
func (r *Repository) GetUserRoleSummary(ctx context.Context, userID int64) (hostdomain.UserRoleSummary, error) {
app := appcode.FromContext(ctx)
summary := hostdomain.UserRoleSummary{UserID: userID}
var hostStatus string
var hostSource string
var hostAgencyID int64
var ownerAgencyID int64
var bdUserID int64
var bdRole string
var bdStatus string
var coinSellerStatus string
var merchantAssetType string
err := r.db.QueryRowContext(ctx, `
SELECT
COALESCE(h.status, ''),
COALESCE(h.source, ''),
COALESCE(h.current_agency_id, 0),
COALESCE(a.agency_id, 0),
COALESCE(b.user_id, 0),
COALESCE(b.role, ''),
COALESCE(b.status, ''),
COALESCE(c.status, ''),
COALESCE(c.merchant_asset_type, '')
FROM (SELECT ? AS user_id) u
LEFT JOIN host_profiles h
ON h.app_code = ? AND h.user_id = u.user_id
LEFT JOIN agencies a
ON a.app_code = ? AND a.owner_user_id = u.user_id AND a.status = ?
LEFT JOIN bd_profiles b
ON b.app_code = ? AND b.user_id = u.user_id
LEFT JOIN coin_seller_profiles c
ON c.app_code = ? AND c.user_id = u.user_id`,
userID,
app,
app, hostdomain.AgencyStatusActive,
app,
app,
).Scan(&hostStatus, &hostSource, &hostAgencyID, &ownerAgencyID, &bdUserID, &bdRole, &bdStatus, &coinSellerStatus, &merchantAssetType)
if err != nil {
return hostdomain.UserRoleSummary{}, err
}
summary.HostStatus = hostStatus
summary.IsHost = hostStatus == hostdomain.HostStatusActive
if ownerAgencyID > 0 {
summary.AgencyID = ownerAgencyID
// 经理中心首版授权边界是 active Agency owner普通 Agency 成员只展示 Agency 入口,不具备 manager 身份。
summary.IsManager = true
} else {
summary.AgencyID = hostAgencyID
}
summary.IsAgency = ownerAgencyID > 0 || (summary.IsHost && (hostSource == hostdomain.HostSourceAgencyInvitation || hostSource == hostdomain.HostSourceAdminCreateAgency))
summary.BDStatus = bdStatus
if bdUserID > 0 && bdStatus == hostdomain.BDStatusActive {
summary.BDID = bdUserID
switch bdRole {
case hostdomain.BDRoleLeader:
summary.IsBD = true
summary.IsBDLeader = true
case hostdomain.BDRoleBD:
summary.IsBD = true
}
}
summary.CoinSellerStatus = coinSellerStatus
summary.IsCoinSeller = coinSellerStatus == hostdomain.CoinSellerStatusActive && merchantAssetType == hostdomain.CoinSellerMerchantAssetType
if err := r.db.QueryRowContext(ctx, `
SELECT COUNT(*)
FROM role_invitations
WHERE app_code = ? AND target_user_id = ? AND status = ?`,
app, userID, hostdomain.InvitationStatusPending,
).Scan(&summary.PendingRoleInvitations); err != nil {
return hostdomain.UserRoleSummary{}, err
}
return summary, nil
}
// HasActiveAgencyOwner 精确判断用户是否为 active Agency owner。
// 普通 Agency 成员会在 UserRoleSummary 中有 Agency 入口,但不能获得经理中心资源赠送权限。
func (r *Repository) HasActiveAgencyOwner(ctx context.Context, userID int64) (int64, bool, error) {
agency, ok, err := queryActiveAgencyByOwner(ctx, r.db, userID, false)
if err != nil || !ok {
return 0, ok, err
}
return agency.AgencyID, true, nil
}
// ListAgencyMembers 读取 Agency 成员关系列表。
func (r *Repository) ListAgencyMembers(ctx context.Context, agencyID int64, status string) ([]hostdomain.AgencyMembership, error) {
query := fmt.Sprintf(`SELECT %s FROM agency_memberships WHERE app_code = ? AND agency_id = ?`, agencyMembershipColumns)
args := []any{appcode.FromContext(ctx), agencyID}
if status != "" {
query += " AND status = ?"
args = append(args, status)
}
query += " ORDER BY joined_at_ms DESC, membership_id DESC"
return queryAgencyMemberships(ctx, r.db, query, args...)
}
// ListAgencyApplications 读取 Agency 申请列表。
func (r *Repository) ListAgencyApplications(ctx context.Context, agencyID int64, status string) ([]hostdomain.AgencyApplication, error) {
query := fmt.Sprintf(`SELECT %s FROM agency_applications WHERE app_code = ? AND agency_id = ?`, agencyApplicationColumns)
args := []any{appcode.FromContext(ctx), agencyID}
if status != "" {
query += " AND status = ?"
args = append(args, status)
}
query += " ORDER BY created_at_ms DESC, application_id DESC"
return queryAgencyApplications(ctx, r.db, query, args...)
}
func queryHostProfile(ctx context.Context, q sqlQueryer, clause string, args ...any) (hostdomain.HostProfile, error) {
clause, args = appScopedClause(ctx, clause, args...)
profile, err := scanHostProfile(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM host_profiles %s`, hostProfileColumns, clause), args...))
if err == sql.ErrNoRows {
return hostdomain.HostProfile{}, xerr.New(xerr.NotFound, "host profile not found")
}
return profile, err
}
func queryHostProfileMaybe(ctx context.Context, q sqlQueryer, userID int64, lock bool) (hostdomain.HostProfile, bool, error) {
clause := "WHERE user_id = ? AND status = ?"
if lock {
clause += " FOR UPDATE"
}
clause, args := appScopedClause(ctx, clause, userID, hostdomain.HostStatusActive)
profile, err := scanHostProfile(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM host_profiles %s`, hostProfileColumns, clause), args...))
if err == sql.ErrNoRows {
return hostdomain.HostProfile{}, false, nil
}
if err != nil {
return hostdomain.HostProfile{}, false, err
}
return profile, true, nil
}
func queryHostProfileByUserMaybe(ctx context.Context, q sqlQueryer, userID int64, lock bool) (hostdomain.HostProfile, bool, error) {
clause := "WHERE user_id = ?"
if lock {
// 后台创建 Agency owner 时需要覆盖 active/disabled 任意主播身份行,避免重复插入主键。
clause += " FOR UPDATE"
}
clause, args := appScopedClause(ctx, clause, userID)
profile, err := scanHostProfile(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM host_profiles %s`, hostProfileColumns, clause), args...))
if err == sql.ErrNoRows {
return hostdomain.HostProfile{}, false, nil
}
if err != nil {
return hostdomain.HostProfile{}, false, err
}
return profile, true, nil
}
func scanHostProfile(scanner rowScanner) (hostdomain.HostProfile, error) {
var profile hostdomain.HostProfile
err := scanner.Scan(
&profile.UserID,
&profile.Status,
&profile.RegionID,
&profile.CurrentAgencyID,
&profile.CurrentMembershipID,
&profile.Source,
&profile.FirstBecameHostAtMs,
&profile.CreatedAtMs,
&profile.UpdatedAtMs,
)
return profile, err
}
func queryAgency(ctx context.Context, q sqlQueryer, clause string, args ...any) (hostdomain.Agency, error) {
clause, args = appScopedClause(ctx, clause, args...)
agency, err := scanAgency(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM agencies %s`, agencyColumns, clause), args...))
if err == sql.ErrNoRows {
return hostdomain.Agency{}, xerr.New(xerr.NotFound, "agency not found")
}
return agency, err
}
func queryActiveAgencyByOwner(ctx context.Context, q sqlQueryer, ownerUserID int64, lock bool) (hostdomain.Agency, bool, error) {
clause := "WHERE owner_user_id = ? AND status = ?"
if lock {
clause += " FOR UPDATE"
}
clause, args := appScopedClause(ctx, clause, ownerUserID, hostdomain.AgencyStatusActive)
agency, err := scanAgency(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM agencies %s`, agencyColumns, clause), args...))
if err == sql.ErrNoRows {
return hostdomain.Agency{}, false, nil
}
if err != nil {
return hostdomain.Agency{}, false, err
}
return agency, true, nil
}
func queryAgencyByOwnerMaybe(ctx context.Context, q sqlQueryer, ownerUserID int64, lock bool) (hostdomain.Agency, bool, error) {
clause := "WHERE owner_user_id = ?"
if lock {
// 后台创建 Agency 时要锁住 owner 名下所有历史 Agency 行,避免 active/closed 切换和新建并发。
clause += " FOR UPDATE"
}
clause, args := appScopedClause(ctx, clause, ownerUserID)
agency, err := scanAgency(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM agencies %s`, agencyColumns, clause), args...))
if err == sql.ErrNoRows {
return hostdomain.Agency{}, false, nil
}
if err != nil {
return hostdomain.Agency{}, false, err
}
return agency, true, nil
}
func scanAgency(scanner rowScanner) (hostdomain.Agency, error) {
var agency hostdomain.Agency
err := scanner.Scan(
&agency.AgencyID,
&agency.OwnerUserID,
&agency.RegionID,
&agency.ParentBDUserID,
&agency.Name,
&agency.Status,
&agency.JoinEnabled,
&agency.MaxHosts,
&agency.CreatedByUserID,
&agency.CreatedAtMs,
&agency.UpdatedAtMs,
)
return agency, err
}
func queryBDProfile(ctx context.Context, q sqlQueryer, clause string, args ...any) (hostdomain.BDProfile, error) {
clause, args = appScopedClause(ctx, clause, args...)
profile, err := scanBDProfile(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM bd_profiles %s`, bdProfileColumns, clause), args...))
if err == sql.ErrNoRows {
return hostdomain.BDProfile{}, xerr.New(xerr.NotFound, "bd profile not found")
}
return profile, err
}
func queryBDProfileMaybe(ctx context.Context, q sqlQueryer, userID int64, lock bool) (hostdomain.BDProfile, bool, error) {
clause := "WHERE user_id = ? AND status = ?"
if lock {
clause += " FOR UPDATE"
}
clause, args := appScopedClause(ctx, clause, userID, hostdomain.BDStatusActive)
profile, err := scanBDProfile(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM bd_profiles %s`, bdProfileColumns, clause), args...))
if err == sql.ErrNoRows {
return hostdomain.BDProfile{}, false, nil
}
if err != nil {
return hostdomain.BDProfile{}, false, err
}
return profile, true, nil
}
func queryBDProfileByUserMaybe(ctx context.Context, q sqlQueryer, userID int64, lock bool) (hostdomain.BDProfile, bool, error) {
clause := "WHERE user_id = ?"
if lock {
// 后台创建/停用角色使用主键锁,覆盖 active 和 disabled 两种状态。
clause += " FOR UPDATE"
}
clause, args := appScopedClause(ctx, clause, userID)
profile, err := scanBDProfile(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM bd_profiles %s`, bdProfileColumns, clause), args...))
if err == sql.ErrNoRows {
return hostdomain.BDProfile{}, false, nil
}
if err != nil {
return hostdomain.BDProfile{}, false, err
}
return profile, true, nil
}
func scanBDProfile(scanner rowScanner) (hostdomain.BDProfile, error) {
var profile hostdomain.BDProfile
err := scanner.Scan(
&profile.UserID,
&profile.Role,
&profile.RegionID,
&profile.ParentLeaderUserID,
&profile.Status,
&profile.CreatedByUserID,
&profile.CreatedAtMs,
&profile.UpdatedAtMs,
)
return profile, err
}
func queryCoinSellerProfile(ctx context.Context, q sqlQueryer, clause string, args ...any) (hostdomain.CoinSellerProfile, error) {
clause, args = appScopedClause(ctx, clause, args...)
profile, err := scanCoinSellerProfile(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM coin_seller_profiles %s`, coinSellerProfileColumns, clause), args...))
if err == sql.ErrNoRows {
return hostdomain.CoinSellerProfile{}, xerr.New(xerr.NotFound, "coin_seller profile not found")
}
return profile, err
}
func queryCoinSellerProfileByUserMaybe(ctx context.Context, q sqlQueryer, userID int64, lock bool) (hostdomain.CoinSellerProfile, bool, error) {
clause := "WHERE user_id = ?"
if lock {
// 币商身份可以和 Agency/BD/BD Leader 并存,但同一用户只能有一条币商身份事实。
clause += " FOR UPDATE"
}
clause, args := appScopedClause(ctx, clause, userID)
profile, err := scanCoinSellerProfile(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM coin_seller_profiles %s`, coinSellerProfileColumns, clause), args...))
if err == sql.ErrNoRows {
return hostdomain.CoinSellerProfile{}, false, nil
}
if err != nil {
return hostdomain.CoinSellerProfile{}, false, err
}
return profile, true, nil
}
func scanCoinSellerProfile(scanner rowScanner) (hostdomain.CoinSellerProfile, error) {
var profile hostdomain.CoinSellerProfile
err := scanner.Scan(
&profile.UserID,
&profile.Status,
&profile.MerchantAssetType,
&profile.CreatedByUserID,
&profile.CreatedAtMs,
&profile.UpdatedAtMs,
)
return profile, err
}
func queryAgencyMembership(ctx context.Context, q sqlQueryer, clause string, args ...any) (hostdomain.AgencyMembership, error) {
clause, args = appScopedClause(ctx, clause, args...)
membership, err := scanAgencyMembership(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM agency_memberships %s`, agencyMembershipColumns, clause), args...))
if err == sql.ErrNoRows {
return hostdomain.AgencyMembership{}, xerr.New(xerr.NotFound, "agency membership not found")
}
return membership, err
}
func queryActiveMembershipByHost(ctx context.Context, q sqlQueryer, hostUserID int64, lock bool) (hostdomain.AgencyMembership, bool, error) {
clause := "WHERE host_user_id = ? AND status = ?"
if lock {
clause += " FOR UPDATE"
}
clause, args := appScopedClause(ctx, clause, hostUserID, hostdomain.MembershipStatusActive)
membership, err := scanAgencyMembership(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM agency_memberships %s`, agencyMembershipColumns, clause), args...))
if err == sql.ErrNoRows {
return hostdomain.AgencyMembership{}, false, nil
}
if err != nil {
return hostdomain.AgencyMembership{}, false, err
}
return membership, true, nil
}
func queryAgencyMemberships(ctx context.Context, q sqlQueryer, query string, args ...any) ([]hostdomain.AgencyMembership, error) {
rows, err := q.QueryContext(ctx, query, args...)
if err != nil {
return nil, err
}
defer rows.Close()
memberships := make([]hostdomain.AgencyMembership, 0)
for rows.Next() {
membership, err := scanAgencyMembership(rows)
if err != nil {
return nil, err
}
memberships = append(memberships, membership)
}
return memberships, rows.Err()
}
func scanAgencyMembership(scanner rowScanner) (hostdomain.AgencyMembership, error) {
var membership hostdomain.AgencyMembership
err := scanner.Scan(
&membership.MembershipID,
&membership.AgencyID,
&membership.HostUserID,
&membership.RegionID,
&membership.MembershipType,
&membership.Status,
&membership.JoinedAtMs,
&membership.EndedAtMs,
&membership.EndedByUserID,
&membership.EndedReason,
&membership.CreatedAtMs,
&membership.UpdatedAtMs,
)
return membership, err
}
func queryAgencyApplication(ctx context.Context, q sqlQueryer, clause string, args ...any) (hostdomain.AgencyApplication, error) {
clause, args = appScopedClause(ctx, clause, args...)
application, err := scanAgencyApplication(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM agency_applications %s`, agencyApplicationColumns, clause), args...))
if err == sql.ErrNoRows {
return hostdomain.AgencyApplication{}, xerr.New(xerr.NotFound, "agency application not found")
}
return application, err
}
func queryAgencyApplications(ctx context.Context, q sqlQueryer, query string, args ...any) ([]hostdomain.AgencyApplication, error) {
rows, err := q.QueryContext(ctx, query, args...)
if err != nil {
return nil, err
}
defer rows.Close()
applications := make([]hostdomain.AgencyApplication, 0)
for rows.Next() {
application, err := scanAgencyApplication(rows)
if err != nil {
return nil, err
}
applications = append(applications, application)
}
return applications, rows.Err()
}
func scanAgencyApplication(scanner rowScanner) (hostdomain.AgencyApplication, error) {
var application hostdomain.AgencyApplication
err := scanner.Scan(
&application.ApplicationID,
&application.CommandID,
&application.ApplicantUserID,
&application.AgencyID,
&application.RegionID,
&application.Status,
&application.ReviewedByUserID,
&application.ReviewReason,
&application.ReviewedAtMs,
&application.CreatedAtMs,
&application.UpdatedAtMs,
)
return application, err
}
func queryRoleInvitation(ctx context.Context, q sqlQueryer, clause string, args ...any) (hostdomain.RoleInvitation, error) {
clause, args = appScopedClause(ctx, clause, args...)
invitation, err := scanRoleInvitation(q.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM role_invitations %s`, roleInvitationColumns, clause), args...))
if err == sql.ErrNoRows {
return hostdomain.RoleInvitation{}, xerr.New(xerr.NotFound, "role invitation not found")
}
return invitation, err
}
func scanRoleInvitation(scanner rowScanner) (hostdomain.RoleInvitation, error) {
var invitation hostdomain.RoleInvitation
err := scanner.Scan(
&invitation.InvitationID,
&invitation.CommandID,
&invitation.InvitationType,
&invitation.Status,
&invitation.InviterUserID,
&invitation.InviterBDUserID,
&invitation.TargetUserID,
&invitation.RegionID,
&invitation.AgencyName,
&invitation.ParentBDUserID,
&invitation.ParentLeaderUserID,
&invitation.ProcessedByUserID,
&invitation.ProcessReason,
&invitation.ProcessedAtMs,
&invitation.CreatedAtMs,
&invitation.UpdatedAtMs,
)
return invitation, err
}
func reviewResultByApplicationID(ctx context.Context, q sqlQueryer, applicationID int64) (hostdomain.ReviewAgencyApplicationResult, error) {
application, err := queryAgencyApplication(ctx, q, "WHERE application_id = ?", applicationID)
if err != nil {
return hostdomain.ReviewAgencyApplicationResult{}, err
}
result := hostdomain.ReviewAgencyApplicationResult{Application: application}
if application.Status == hostdomain.ApplicationStatusApproved {
profile, err := queryHostProfile(ctx, q, "WHERE user_id = ?", application.ApplicantUserID)
if err != nil {
return hostdomain.ReviewAgencyApplicationResult{}, err
}
membership, err := queryAgencyMembership(ctx, q, "WHERE membership_id = ?", profile.CurrentMembershipID)
if err != nil {
return hostdomain.ReviewAgencyApplicationResult{}, err
}
result.HostProfile = profile
result.Membership = membership
}
return result, nil
}
func kickResultByMembershipID(ctx context.Context, q sqlQueryer, membershipID int64) (hostdomain.KickAgencyHostResult, error) {
membership, err := queryAgencyMembership(ctx, q, "WHERE membership_id = ?", membershipID)
if err != nil {
return hostdomain.KickAgencyHostResult{}, err
}
profile, err := queryHostProfile(ctx, q, "WHERE user_id = ?", membership.HostUserID)
if err != nil {
return hostdomain.KickAgencyHostResult{}, err
}
return hostdomain.KickAgencyHostResult{Membership: membership, HostProfile: profile}, nil
}
func processResultByInvitationID(ctx context.Context, q sqlQueryer, invitationID int64) (hostdomain.ProcessRoleInvitationResult, error) {
invitation, err := queryRoleInvitation(ctx, q, "WHERE invitation_id = ?", invitationID)
if err != nil {
return hostdomain.ProcessRoleInvitationResult{}, err
}
result := hostdomain.ProcessRoleInvitationResult{Invitation: invitation}
if invitation.Status != hostdomain.InvitationStatusAccepted {
return result, nil
}
if invitation.InvitationType == hostdomain.InvitationTypeAgency {
if profile, err := queryHostProfile(ctx, q, "WHERE user_id = ?", invitation.TargetUserID); err == nil {
result.HostProfile = profile
if profile.CurrentMembershipID > 0 {
result.Membership, _ = queryAgencyMembership(ctx, q, "WHERE membership_id = ?", profile.CurrentMembershipID)
}
}
if agency, ok, err := queryActiveAgencyByOwner(ctx, q, invitation.TargetUserID, false); err != nil {
return hostdomain.ProcessRoleInvitationResult{}, err
} else if ok {
result.Agency = agency
}
} else if invitation.InvitationType == hostdomain.InvitationTypeBD {
if bd, err := queryBDProfile(ctx, q, "WHERE user_id = ?", invitation.TargetUserID); err == nil {
result.BDProfile = bd
}
}
return result, nil
}