Files
egbim_homepage/egbim/bbs/descope_user_list_w2.php
2026-07-23 16:15:57 +09:00

261 lines
9.2 KiB
PHP

<?php
header('Content-Type: application/json');
// ✅ 타임존 설정 및 디버그용 메타 정보
date_default_timezone_set('Asia/Seoul');
$server_timezone = date_default_timezone_get();
$server_time = date('Y-m-d H:i:s');
// ✅ Descope Management Key
$management_key = 'P2wON5fy1K6kyia269VpeIzYP8oP:K32l5ORmzy32OvaaPvpdZsMY3JmKQb7a3vvrl10PgjlJUGk3K7EssMH3uW5VGQSbrgtEdPj';
$headers = [
"Authorization: Bearer $management_key",
"Content-Type: application/json"
];
$all_users = [];
$page = 0;
$limit = 200;
// ✅ 1) Descope 전체 유저 조회
do {
$url_users = "https://api.descope.com/v2/mgmt/user/search";
$payload = json_encode(["limit" => $limit, "page" => $page]);
$ch = curl_init($url_users);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($http_code !== 200) {
echo json_encode(['status' => 'fail', 'step' => 'user_search', 'code' => $http_code, 'raw' => $response]);
exit;
}
$res = json_decode($response, true);
$users = $res['users'] ?? [];
$all_users = array_merge($all_users, $users);
$page++;
} while (count($users) === $limit);
// ✅ 2) MySQL에서 최근 로그인 시간 병합
try {
$dbHost = getenv('G5_MYSQL_HOST') ?: getenv('MARIADB_HOST') ?: getenv('MYSQL_HOST') ?: 'localhost';
$dbName = getenv('G5_MYSQL_DB') ?: getenv('MARIADB_DATABASE') ?: getenv('MYSQL_DATABASE') ?: 'egbim';
$dbUser = getenv('G5_MYSQL_USER') ?: getenv('MARIADB_USER') ?: getenv('MYSQL_USER') ?: 'egbim';
$dbPass = getenv('G5_MYSQL_PASSWORD') ?: getenv('MARIADB_PASSWORD') ?: getenv('MYSQL_PASSWORD') ?: 'baron3840!!';
$pdo = new PDO("mysql:host={$dbHost};dbname={$dbName};charset=utf8mb4", $dbUser, $dbPass, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
$stmt = $pdo->query("
SELECT
login_id,
MAX(user_login_time) AS last_login_time,
SUM(
CASE
WHEN product_name IN ('eg-bim', 'EG-BIM')
AND user_login_time >= DATE_SUB(NOW(), INTERVAL 1 MONTH)
THEN 1 ELSE 0
END
) AS recent_login_count_1m,
COUNT(
DISTINCT CASE
WHEN product_name IN ('eg-bim', 'EG-BIM')
AND created_at >= DATE_SUB(NOW(), INTERVAL 1 MONTH)
THEN DATE(created_at)
ELSE NULL
END
) AS recent_login_days_1m
FROM user_program_info
WHERE (
(user_login_time IS NOT NULL AND user_login_time <> '')
OR created_at IS NOT NULL
)
GROUP BY login_id
");
$loginMap = [];
$recentLoginCount1mMap = [];
$recentLoginDays1mMap = [];
while ($row = $stmt->fetch()) {
$loginMap[$row['login_id']] = $row['last_login_time'];
$recentLoginCount1mMap[$row['login_id']] = (int) ($row['recent_login_count_1m'] ?? 0);
$recentLoginDays1mMap[$row['login_id']] = (int) ($row['recent_login_days_1m'] ?? 0);
}
} catch (Exception $e) {
$loginMap = [];
$recentLoginCount1mMap = [];
$recentLoginDays1mMap = [];
}
// ✅ 3) 날짜 변환 함수 (KST 환경 기준 — 이중 변환 방지)
$fmtDate = function($val) {
if (empty($val)) return null;
if (!is_numeric($val)) return null;
$ts = (float) $val;
if ($ts > 1e12) $ts = $ts / 1000; // 밀리초 → 초 변환
$ts = (int) round($ts);
if ($ts <= 0) return null;
// ✅ UTC 기준으로 그대로 출력 (PHP의 +9h 보정 방지)
return gmdate('Y-m-d H:i:s', $ts);
};
// ✅ 4) 유저 데이터 가공
foreach ($all_users as &$u) {
$u['customAttributes'] = $u['customAttributes'] ?? [];
$u['name'] = $u['name'] ?? '';
$u['email'] = $u['email'] ?? '';
$u['phone'] = $u['phone'] ?? '';
// --- 테넌트 이름 문자열화 ---
if (!empty($u['userTenants']) && is_array($u['userTenants'])) {
$tenantNames = [];
foreach ($u['userTenants'] as $t) {
$tenantNames[] = $t['tenantName'] ?? $t['tenantId'] ?? '';
}
$u['tenantText'] = implode(', ', array_filter($tenantNames));
} else {
$u['tenantText'] = '-';
}
// --- createdTime ---
if (!empty($u['createdTime'])) {
$u['createdTime'] = $fmtDate($u['createdTime']);
}
// --- egBimLExpiryDate ---
if (!empty($u['customAttributes']['egBimLExpiryDate'])) {
$u['customAttributes']['egBimLExpiryDate'] = $fmtDate($u['customAttributes']['egBimLExpiryDate']);
}
// --- lastSignInDate ---
if (!empty($u['customAttributes']['lastSignInDate'])) {
$u['customAttributes']['lastSignInDate'] = $fmtDate($u['customAttributes']['lastSignInDate']);
}
// --- serverLastLogin (EGBIM DB 병합) ---
$loginId = $u['loginIds'][0] ?? null;
if ($loginId && isset($loginMap[$loginId])) {
$u['customAttributes']['serverLastLogin'] = $loginMap[$loginId];
}
$u['customAttributes']['recentLoginCount1m'] = $loginId && isset($recentLoginCount1mMap[$loginId])
? $recentLoginCount1mMap[$loginId]
: 0;
$u['customAttributes']['recentLoginDays1m'] = $loginId && isset($recentLoginDays1mMap[$loginId])
? $recentLoginDays1mMap[$loginId]
: 0;
// --- completeForm 표시를 true/false → 텍스트로 ---
if (isset($u['customAttributes']['completeForm'])) {
$u['customAttributes']['completeForm'] = $u['customAttributes']['completeForm'] ? '완료' : '미완료';
}
}
unset($u);
// ✅ 5) 필터링
$start = $_GET['start'] ?? null;
$end = $_GET['end'] ?? null;
$mode = $_GET['mode'] ?? 'created';
$keyword = $_GET['keyword'] ?? '';
$tenantFilters = isset($_GET['tenants']) ? explode(',', $_GET['tenants']) : [];
function normalize_ts($val) {
$ts = (int)$val;
if ($ts > 0 && $ts < 1e12) $ts *= 1000;
return $ts;
}
// --- 기간 필터 ---
if ($start || $end) {
$startTs = $start ? strtotime($start . " 00:00:00") * 1000 : null;
$endTs = $end ? strtotime($end . " 23:59:59") * 1000 : null;
$all_users = array_filter($all_users, function($u) use ($startTs, $endTs, $mode) {
$ts = 0;
if ($mode === 'created') {
$ts = strtotime($u['createdTime'] ?? '') * 1000;
} elseif ($mode === 'lastSignIn') {
$ts = strtotime($u['customAttributes']['lastSignInDate'] ?? '') * 1000;
} elseif ($mode === 'license') {
$ts = strtotime($u['customAttributes']['egBimLExpiryDate'] ?? '') * 1000;
} elseif ($mode === 'serverLogin') {
if (!empty($u['customAttributes']['serverLastLogin'])) {
$ts = strtotime($u['customAttributes']['serverLastLogin']) * 1000;
}
}
if (!$ts) return false;
if ($startTs && $ts < $startTs) return false;
if ($endTs && $ts > $endTs) return false;
return true;
});
$all_users = array_values($all_users);
}
// --- 테넌트 필터 ---
if (!empty($tenantFilters)) {
$all_users = array_filter($all_users, function($u) use ($tenantFilters) {
$txt = $u['tenantText'] ?? '';
foreach ($tenantFilters as $t) {
if (stripos($txt, $t) !== false) return true;
}
return false;
});
$all_users = array_values($all_users);
}
// --- 키워드 필터 ---
if ($keyword !== '') {
$all_users = array_filter($all_users, function($u) use ($keyword) {
$fields = [
$u['customAttributes']['familyCompany'] ?? '',
$u['customAttributes']['company'] ?? '',
$u['name'] ?? '',
$u['displayName'] ?? ''
];
foreach ($fields as $f) {
if (stripos($f, $keyword) !== false) return true;
}
return false;
});
$all_users = array_values($all_users);
}
// --- 정렬 ---
usort($all_users, function($a, $b) use ($mode) {
if ($mode === 'created') {
return strcmp($b['createdTime'] ?? '', $a['createdTime'] ?? '');
} elseif ($mode === 'lastSignIn') {
return strcmp($b['customAttributes']['lastSignInDate'] ?? '', $a['customAttributes']['lastSignInDate'] ?? '');
} elseif ($mode === 'license') {
return strcmp($b['customAttributes']['egBimLExpiryDate'] ?? '', $a['customAttributes']['egBimLExpiryDate'] ?? '');
} elseif ($mode === 'serverLogin') {
return strcmp($b['customAttributes']['serverLastLogin'] ?? '', $a['customAttributes']['serverLastLogin'] ?? '');
}
return 0;
});
// ✅ 6) 최종 응답 (타임존 정보 포함)
echo json_encode([
'status' => 'success', // ✅ "ok" 대신 "success"로
'total' => count($all_users),
'records' => $all_users,
'msg' => '', // ✅ w2ui 기본 필드 추가
'meta' => [
'timezone' => $server_timezone,
'server_time' => $server_time
]
], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
?>