feat: 支持按时区查询活跃用户时间窗
This commit is contained in:
@@ -28,9 +28,17 @@ def credits_all_users(token):
|
||||
return users
|
||||
page += 1
|
||||
|
||||
def credits_active_usage(token, since):
|
||||
end_at = datetime.now(timezone.utc)
|
||||
start_at = credits_window_start(since, end_at)
|
||||
def credits_active_usage(token, since, active_start, active_end, active_start_utc, active_end_utc, timezone_name):
|
||||
if since:
|
||||
end_at = datetime.now(timezone.utc)
|
||||
start_at = credits_window_start(since, end_at)
|
||||
selection_kind = "active-users"
|
||||
else:
|
||||
start_at = credits_parse_time(active_start_utc)
|
||||
end_at = credits_parse_time(active_end_utc)
|
||||
selection_kind = "active-window"
|
||||
if start_at is None or end_at is None or end_at <= start_at:
|
||||
raise RuntimeError("credits active window end must be after start")
|
||||
user_requests = {}
|
||||
page = 1
|
||||
while True:
|
||||
@@ -46,11 +54,19 @@ def credits_active_usage(token, since):
|
||||
reached_start = True
|
||||
continue
|
||||
user_id = row.get("user_id") if row.get("user_id") is not None else row.get("userId")
|
||||
if user_id is not None and (created_at is None or created_at <= end_at):
|
||||
if user_id is not None and created_at is not None and start_at <= created_at < end_at:
|
||||
user_requests[str(user_id)] = user_requests.get(str(user_id), 0) + 1
|
||||
total = int(data.get("total", 0)) if isinstance(data, dict) else 0
|
||||
if not batch or len(batch) < 100 or reached_start or page * 100 >= total:
|
||||
return user_requests, start_at, end_at
|
||||
return user_requests, start_at, end_at, {
|
||||
"kind": selection_kind,
|
||||
"since": since,
|
||||
"timezone": timezone_name if selection_kind == "active-window" else "UTC",
|
||||
"startAt": active_start if selection_kind == "active-window" else start_at.isoformat(),
|
||||
"endAt": active_end if selection_kind == "active-window" else end_at.isoformat(),
|
||||
"startAtUtc": start_at.isoformat().replace("+00:00", "Z"),
|
||||
"endAtUtc": end_at.isoformat().replace("+00:00", "Z"),
|
||||
}
|
||||
page += 1
|
||||
|
||||
def credits_selected_users(token, payload):
|
||||
@@ -58,8 +74,13 @@ def credits_selected_users(token, payload):
|
||||
users_by_id = {str(item.get("id")): item for item in users if item.get("id") is not None}
|
||||
users_by_email = {str(item.get("email") or "").strip().lower(): item for item in users if item.get("email")}
|
||||
active_since = payload.get("activeSince")
|
||||
if active_since:
|
||||
requests, start_at, end_at = credits_active_usage(token, active_since)
|
||||
active_start = payload.get("activeStart")
|
||||
active_end = payload.get("activeEnd")
|
||||
if active_since or (active_start and active_end):
|
||||
requests, _, _, selection = credits_active_usage(
|
||||
token, active_since, active_start, active_end,
|
||||
payload.get("activeStartUtc"), payload.get("activeEndUtc"), payload.get("timezone"),
|
||||
)
|
||||
selected = []
|
||||
excluded = []
|
||||
for user_id, request_count in requests.items():
|
||||
@@ -72,7 +93,7 @@ def credits_selected_users(token, payload):
|
||||
excluded.append({"userId": user.get("id"), "email": user.get("email"), "reason": "inactive-or-deleted"})
|
||||
else:
|
||||
selected.append((user, request_count))
|
||||
return selected, excluded, {"kind": "active-users", "since": active_since, "startAt": start_at.isoformat(), "endAt": end_at.isoformat()}
|
||||
return selected, excluded, selection
|
||||
selected = []
|
||||
seen = set()
|
||||
for selector in payload.get("users") or []:
|
||||
|
||||
Reference in New Issue
Block a user