user list response fix
This commit is contained in:
parent
2883561525
commit
f824c16c64
|
|
@ -61,6 +61,29 @@ FROM user_subscriptions us
|
||||||
JOIN subscription_plans sp ON sp.id = us.plan_id
|
JOIN subscription_plans sp ON sp.id = us.plan_id
|
||||||
WHERE us.id = $1;
|
WHERE us.id = $1;
|
||||||
|
|
||||||
|
-- name: ListActiveSubscriptionsByUserIDs :many
|
||||||
|
-- One ACTIVE, non-expired row per user (latest expires_at wins), same rules as GetActiveSubscriptionByUserID.
|
||||||
|
SELECT DISTINCT ON (us.user_id)
|
||||||
|
us.user_id,
|
||||||
|
us.id,
|
||||||
|
us.plan_id,
|
||||||
|
us.starts_at,
|
||||||
|
us.expires_at,
|
||||||
|
us.status,
|
||||||
|
us.auto_renew,
|
||||||
|
us.payment_method,
|
||||||
|
sp.name AS plan_name,
|
||||||
|
sp.duration_value,
|
||||||
|
sp.duration_unit,
|
||||||
|
sp.price,
|
||||||
|
sp.currency
|
||||||
|
FROM user_subscriptions us
|
||||||
|
JOIN subscription_plans sp ON sp.id = us.plan_id
|
||||||
|
WHERE us.user_id = ANY($1::bigint[])
|
||||||
|
AND us.status = 'ACTIVE'
|
||||||
|
AND us.expires_at > CURRENT_TIMESTAMP
|
||||||
|
ORDER BY us.user_id, us.expires_at DESC;
|
||||||
|
|
||||||
-- name: GetActiveSubscriptionByUserID :one
|
-- name: GetActiveSubscriptionByUserID :one
|
||||||
SELECT
|
SELECT
|
||||||
us.*,
|
us.*,
|
||||||
|
|
|
||||||
46
docs/docs.go
46
docs/docs.go
|
|
@ -8436,7 +8436,7 @@ const docTemplate = `{
|
||||||
},
|
},
|
||||||
"/api/v1/users": {
|
"/api/v1/users": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Get users with optional filters",
|
"description": "Get users with optional filters. Each user may include active_subscription when they have a current ACTIVE, non-expired plan.",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
|
|
@ -11294,6 +11294,9 @@ const docTemplate = `{
|
||||||
"domain.UserProfileResponse": {
|
"domain.UserProfileResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"active_subscription": {
|
||||||
|
"$ref": "#/definitions/domain.UserSubscriptionSummary"
|
||||||
|
},
|
||||||
"age_group": {
|
"age_group": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|
@ -11401,6 +11404,47 @@ const docTemplate = `{
|
||||||
"UserStatusDeactivated"
|
"UserStatusDeactivated"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"domain.UserSubscriptionSummary": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"auto_renew": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"currency": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"duration_unit": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"duration_value": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"expires_at": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"payment_method": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"plan_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"plan_name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"price": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"starts_at": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"domain.UserSummary": {
|
"domain.UserSummary": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
|
||||||
|
|
@ -8428,7 +8428,7 @@
|
||||||
},
|
},
|
||||||
"/api/v1/users": {
|
"/api/v1/users": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Get users with optional filters",
|
"description": "Get users with optional filters. Each user may include active_subscription when they have a current ACTIVE, non-expired plan.",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
|
|
@ -11286,6 +11286,9 @@
|
||||||
"domain.UserProfileResponse": {
|
"domain.UserProfileResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"active_subscription": {
|
||||||
|
"$ref": "#/definitions/domain.UserSubscriptionSummary"
|
||||||
|
},
|
||||||
"age_group": {
|
"age_group": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|
@ -11393,6 +11396,47 @@
|
||||||
"UserStatusDeactivated"
|
"UserStatusDeactivated"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"domain.UserSubscriptionSummary": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"auto_renew": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"currency": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"duration_unit": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"duration_value": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"expires_at": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"payment_method": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"plan_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"plan_name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"price": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"starts_at": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"domain.UserSummary": {
|
"domain.UserSummary": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
|
||||||
|
|
@ -1145,6 +1145,8 @@ definitions:
|
||||||
type: object
|
type: object
|
||||||
domain.UserProfileResponse:
|
domain.UserProfileResponse:
|
||||||
properties:
|
properties:
|
||||||
|
active_subscription:
|
||||||
|
$ref: '#/definitions/domain.UserSubscriptionSummary'
|
||||||
age_group:
|
age_group:
|
||||||
type: string
|
type: string
|
||||||
birth_day:
|
birth_day:
|
||||||
|
|
@ -1219,6 +1221,33 @@ definitions:
|
||||||
- UserStatusActive
|
- UserStatusActive
|
||||||
- UserStatusSuspended
|
- UserStatusSuspended
|
||||||
- UserStatusDeactivated
|
- UserStatusDeactivated
|
||||||
|
domain.UserSubscriptionSummary:
|
||||||
|
properties:
|
||||||
|
auto_renew:
|
||||||
|
type: boolean
|
||||||
|
currency:
|
||||||
|
type: string
|
||||||
|
duration_unit:
|
||||||
|
type: string
|
||||||
|
duration_value:
|
||||||
|
type: integer
|
||||||
|
expires_at:
|
||||||
|
type: string
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
payment_method:
|
||||||
|
type: string
|
||||||
|
plan_id:
|
||||||
|
type: integer
|
||||||
|
plan_name:
|
||||||
|
type: string
|
||||||
|
price:
|
||||||
|
type: number
|
||||||
|
starts_at:
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
domain.UserSummary:
|
domain.UserSummary:
|
||||||
properties:
|
properties:
|
||||||
active_users:
|
active_users:
|
||||||
|
|
@ -7988,7 +8017,8 @@ paths:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: Get users with optional filters
|
description: Get users with optional filters. Each user may include active_subscription
|
||||||
|
when they have a current ACTIVE, non-expired plan.
|
||||||
parameters:
|
parameters:
|
||||||
- description: Role filter
|
- description: Role filter
|
||||||
in: query
|
in: query
|
||||||
|
|
|
||||||
|
|
@ -578,6 +578,80 @@ func (q *Queries) ListActiveSubscriptionPlans(ctx context.Context) ([]Subscripti
|
||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ListActiveSubscriptionsByUserIDs = `-- name: ListActiveSubscriptionsByUserIDs :many
|
||||||
|
SELECT DISTINCT ON (us.user_id)
|
||||||
|
us.user_id,
|
||||||
|
us.id,
|
||||||
|
us.plan_id,
|
||||||
|
us.starts_at,
|
||||||
|
us.expires_at,
|
||||||
|
us.status,
|
||||||
|
us.auto_renew,
|
||||||
|
us.payment_method,
|
||||||
|
sp.name AS plan_name,
|
||||||
|
sp.duration_value,
|
||||||
|
sp.duration_unit,
|
||||||
|
sp.price,
|
||||||
|
sp.currency
|
||||||
|
FROM user_subscriptions us
|
||||||
|
JOIN subscription_plans sp ON sp.id = us.plan_id
|
||||||
|
WHERE us.user_id = ANY($1::bigint[])
|
||||||
|
AND us.status = 'ACTIVE'
|
||||||
|
AND us.expires_at > CURRENT_TIMESTAMP
|
||||||
|
ORDER BY us.user_id, us.expires_at DESC
|
||||||
|
`
|
||||||
|
|
||||||
|
type ListActiveSubscriptionsByUserIDsRow struct {
|
||||||
|
UserID int64 `json:"user_id"`
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
PlanID int64 `json:"plan_id"`
|
||||||
|
StartsAt pgtype.Timestamptz `json:"starts_at"`
|
||||||
|
ExpiresAt pgtype.Timestamptz `json:"expires_at"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
AutoRenew bool `json:"auto_renew"`
|
||||||
|
PaymentMethod pgtype.Text `json:"payment_method"`
|
||||||
|
PlanName string `json:"plan_name"`
|
||||||
|
DurationValue int32 `json:"duration_value"`
|
||||||
|
DurationUnit string `json:"duration_unit"`
|
||||||
|
Price pgtype.Numeric `json:"price"`
|
||||||
|
Currency string `json:"currency"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// One ACTIVE, non-expired row per user (latest expires_at wins), same rules as GetActiveSubscriptionByUserID.
|
||||||
|
func (q *Queries) ListActiveSubscriptionsByUserIDs(ctx context.Context, dollar_1 []int64) ([]ListActiveSubscriptionsByUserIDsRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, ListActiveSubscriptionsByUserIDs, dollar_1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []ListActiveSubscriptionsByUserIDsRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i ListActiveSubscriptionsByUserIDsRow
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.UserID,
|
||||||
|
&i.ID,
|
||||||
|
&i.PlanID,
|
||||||
|
&i.StartsAt,
|
||||||
|
&i.ExpiresAt,
|
||||||
|
&i.Status,
|
||||||
|
&i.AutoRenew,
|
||||||
|
&i.PaymentMethod,
|
||||||
|
&i.PlanName,
|
||||||
|
&i.DurationValue,
|
||||||
|
&i.DurationUnit,
|
||||||
|
&i.Price,
|
||||||
|
&i.Currency,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
const ListSubscriptionPlans = `-- name: ListSubscriptionPlans :many
|
const ListSubscriptionPlans = `-- name: ListSubscriptionPlans :many
|
||||||
SELECT id, name, description, duration_value, duration_unit, price, currency, is_active, created_at, updated_at FROM subscription_plans
|
SELECT id, name, description, duration_value, duration_unit, price, currency, is_active, created_at, updated_at FROM subscription_plans
|
||||||
WHERE ($1::BOOLEAN IS NULL OR $1 = true AND is_active = true OR $1 = false)
|
WHERE ($1::BOOLEAN IS NULL OR $1 = true AND is_active = true OR $1 = false)
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,54 @@ type UserSubscription struct {
|
||||||
Currency *string
|
Currency *string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UserSubscriptionSummary is the active subscription attached to admin user list responses (GET /users).
|
||||||
|
type UserSubscriptionSummary struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
PlanID int64 `json:"plan_id"`
|
||||||
|
PlanName string `json:"plan_name"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
StartsAt time.Time `json:"starts_at"`
|
||||||
|
ExpiresAt time.Time `json:"expires_at"`
|
||||||
|
AutoRenew bool `json:"auto_renew"`
|
||||||
|
PaymentMethod *string `json:"payment_method,omitempty"`
|
||||||
|
DurationValue int32 `json:"duration_value"`
|
||||||
|
DurationUnit string `json:"duration_unit"`
|
||||||
|
Price float64 `json:"price"`
|
||||||
|
Currency string `json:"currency"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Summary returns a copy safe for JSON embedding; nil if receiver is nil.
|
||||||
|
func (us *UserSubscription) Summary() *UserSubscriptionSummary {
|
||||||
|
if us == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
s := &UserSubscriptionSummary{
|
||||||
|
ID: us.ID,
|
||||||
|
PlanID: us.PlanID,
|
||||||
|
Status: us.Status,
|
||||||
|
StartsAt: us.StartsAt,
|
||||||
|
ExpiresAt: us.ExpiresAt,
|
||||||
|
AutoRenew: us.AutoRenew,
|
||||||
|
PaymentMethod: us.PaymentMethod,
|
||||||
|
}
|
||||||
|
if us.PlanName != nil {
|
||||||
|
s.PlanName = *us.PlanName
|
||||||
|
}
|
||||||
|
if us.DurationValue != nil {
|
||||||
|
s.DurationValue = *us.DurationValue
|
||||||
|
}
|
||||||
|
if us.DurationUnit != nil {
|
||||||
|
s.DurationUnit = *us.DurationUnit
|
||||||
|
}
|
||||||
|
if us.Price != nil {
|
||||||
|
s.Price = *us.Price
|
||||||
|
}
|
||||||
|
if us.Currency != nil {
|
||||||
|
s.Currency = *us.Currency
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
type CreateSubscriptionPlanInput struct {
|
type CreateSubscriptionPlanInput struct {
|
||||||
Name string
|
Name string
|
||||||
Description *string
|
Description *string
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,8 @@ type UserProfileResponse struct {
|
||||||
|
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
||||||
|
|
||||||
|
ActiveSubscription *UserSubscriptionSummary `json:"active_subscription,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserFilter struct {
|
type UserFilter struct {
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ type SubscriptionStore interface {
|
||||||
CreateUserSubscription(ctx context.Context, input domain.CreateUserSubscriptionInput) (*domain.UserSubscription, error)
|
CreateUserSubscription(ctx context.Context, input domain.CreateUserSubscriptionInput) (*domain.UserSubscription, error)
|
||||||
GetUserSubscriptionByID(ctx context.Context, id int64) (*domain.UserSubscription, error)
|
GetUserSubscriptionByID(ctx context.Context, id int64) (*domain.UserSubscription, error)
|
||||||
GetActiveSubscriptionByUserID(ctx context.Context, userID int64) (*domain.UserSubscription, error)
|
GetActiveSubscriptionByUserID(ctx context.Context, userID int64) (*domain.UserSubscription, error)
|
||||||
|
ListActiveSubscriptionsByUserIDs(ctx context.Context, userIDs []int64) (map[int64]*domain.UserSubscription, error)
|
||||||
GetUserSubscriptionHistory(ctx context.Context, userID int64, limit, offset int32) ([]domain.UserSubscription, error)
|
GetUserSubscriptionHistory(ctx context.Context, userID int64, limit, offset int32) ([]domain.UserSubscription, error)
|
||||||
HasActiveSubscription(ctx context.Context, userID int64) (bool, error)
|
HasActiveSubscription(ctx context.Context, userID int64) (bool, error)
|
||||||
CancelUserSubscription(ctx context.Context, id int64) error
|
CancelUserSubscription(ctx context.Context, id int64) error
|
||||||
|
|
|
||||||
|
|
@ -157,6 +157,39 @@ func (s *Store) GetActiveSubscriptionByUserID(ctx context.Context, userID int64)
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Store) ListActiveSubscriptionsByUserIDs(ctx context.Context, userIDs []int64) (map[int64]*domain.UserSubscription, error) {
|
||||||
|
if len(userIDs) == 0 {
|
||||||
|
return map[int64]*domain.UserSubscription{}, nil
|
||||||
|
}
|
||||||
|
rows, err := s.queries.ListActiveSubscriptionsByUserIDs(ctx, userIDs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
out := make(map[int64]*domain.UserSubscription, len(rows))
|
||||||
|
for _, r := range rows {
|
||||||
|
dv := r.DurationValue
|
||||||
|
du := r.DurationUnit
|
||||||
|
pn := r.PlanName
|
||||||
|
cur := r.Currency
|
||||||
|
out[r.UserID] = &domain.UserSubscription{
|
||||||
|
ID: r.ID,
|
||||||
|
UserID: r.UserID,
|
||||||
|
PlanID: r.PlanID,
|
||||||
|
StartsAt: r.StartsAt.Time,
|
||||||
|
ExpiresAt: r.ExpiresAt.Time,
|
||||||
|
Status: r.Status,
|
||||||
|
AutoRenew: r.AutoRenew,
|
||||||
|
PaymentMethod: fromPgText(r.PaymentMethod),
|
||||||
|
PlanName: &pn,
|
||||||
|
DurationValue: &dv,
|
||||||
|
DurationUnit: &du,
|
||||||
|
Price: float64Ptr(fromPgNumeric(r.Price)),
|
||||||
|
Currency: &cur,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Store) GetUserSubscriptionHistory(ctx context.Context, userID int64, limit, offset int32) ([]domain.UserSubscription, error) {
|
func (s *Store) GetUserSubscriptionHistory(ctx context.Context, userID int64, limit, offset int32) ([]domain.UserSubscription, error) {
|
||||||
subs, err := s.queries.GetUserSubscriptionHistory(ctx, dbgen.GetUserSubscriptionHistoryParams{
|
subs, err := s.queries.GetUserSubscriptionHistory(ctx, dbgen.GetUserSubscriptionHistoryParams{
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,11 @@ func (s *Service) GetActiveSubscription(ctx context.Context, userID int64) (*dom
|
||||||
return s.store.GetActiveSubscriptionByUserID(ctx, userID)
|
return s.store.GetActiveSubscriptionByUserID(ctx, userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListActiveSubscriptionsForUserIDs returns the current ACTIVE, non-expired subscription per user (latest expiry).
|
||||||
|
func (s *Service) ListActiveSubscriptionsForUserIDs(ctx context.Context, userIDs []int64) (map[int64]*domain.UserSubscription, error) {
|
||||||
|
return s.store.ListActiveSubscriptionsByUserIDs(ctx, userIDs)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) GetSubscriptionHistory(ctx context.Context, userID int64, limit, offset int32) ([]domain.UserSubscription, error) {
|
func (s *Service) GetSubscriptionHistory(ctx context.Context, userID int64, limit, offset int32) ([]domain.UserSubscription, error) {
|
||||||
return s.store.GetUserSubscriptionHistory(ctx, userID, limit, offset)
|
return s.store.GetUserSubscriptionHistory(ctx, userID, limit, offset)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -423,7 +423,7 @@ func (h *Handler) CheckUserPending(c *fiber.Ctx) error {
|
||||||
|
|
||||||
// GetAllUsers godoc
|
// GetAllUsers godoc
|
||||||
// @Summary Get all users
|
// @Summary Get all users
|
||||||
// @Description Get users with optional filters
|
// @Description Get users with optional filters. Each user may include active_subscription when they have a current ACTIVE, non-expired plan.
|
||||||
// @Tags user
|
// @Tags user
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
|
|
@ -499,6 +499,19 @@ func (h *Handler) GetAllUsers(c *fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get users: "+err.Error())
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get users: "+err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
userIDs := make([]int64, len(users))
|
||||||
|
for i, u := range users {
|
||||||
|
userIDs[i] = u.ID
|
||||||
|
}
|
||||||
|
activeSubs, err := h.subscriptionsSvc.ListActiveSubscriptionsForUserIDs(c.Context(), userIDs)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("failed to batch-load active subscriptions for user list",
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()))
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get subscription info: "+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
// Map to profile response to avoid leaking sensitive fields
|
// Map to profile response to avoid leaking sensitive fields
|
||||||
// result := make([]domain.UserProfileResponse, len(users))
|
// result := make([]domain.UserProfileResponse, len(users))
|
||||||
// for i, u := range users {
|
// for i, u := range users {
|
||||||
|
|
@ -538,6 +551,11 @@ func (h *Handler) GetAllUsers(c *fiber.Ctx) error {
|
||||||
if !u.BirthDay.IsZero() {
|
if !u.BirthDay.IsZero() {
|
||||||
bd = u.BirthDay.Format("2006-01-02")
|
bd = u.BirthDay.Format("2006-01-02")
|
||||||
}
|
}
|
||||||
|
var activeSub *domain.UserSubscriptionSummary
|
||||||
|
if sub, ok := activeSubs[u.ID]; ok {
|
||||||
|
activeSub = sub.Summary()
|
||||||
|
}
|
||||||
|
|
||||||
mapped = append(mapped, domain.UserProfileResponse{
|
mapped = append(mapped, domain.UserProfileResponse{
|
||||||
ID: u.ID,
|
ID: u.ID,
|
||||||
FirstName: u.FirstName,
|
FirstName: u.FirstName,
|
||||||
|
|
@ -567,6 +585,7 @@ func (h *Handler) GetAllUsers(c *fiber.Ctx) error {
|
||||||
PreferredLanguage: u.PreferredLanguage,
|
PreferredLanguage: u.PreferredLanguage,
|
||||||
CreatedAt: u.CreatedAt,
|
CreatedAt: u.CreatedAt,
|
||||||
UpdatedAt: u.UpdatedAt,
|
UpdatedAt: u.UpdatedAt,
|
||||||
|
ActiveSubscription: activeSub,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user