diff --git a/api/admin/reports/index.php b/api/admin/reports/index.php
new file mode 100644
index 0000000..756eddc
--- /dev/null
+++ b/api/admin/reports/index.php
@@ -0,0 +1,141 @@
+ PDO::ERRMODE_EXCEPTION,
+ PDO::MYSQL_ATTR_MULTI_STATEMENTS => false
+ );
+ $pdo = new PDO('mysql:charset=utf8mb4;dbname=' . DB_NAME . ';host=' . DB_HOST, DB_USER, DB_PASS, $option);
+} catch (PDOException $e) {
+ // 接続エラーのときエラー内容を取得する
+ $error_message[] = $e->getMessage();
+}
+
+if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
+ http_response_code(405);
+ echo json_encode([
+ 'error_code' => 'method_not_allowed',
+ 'success' => false
+ ]);
+ exit;
+}
+
+$Get_Post_Json = file_get_contents("php://input");
+if ((!(empty($Get_Post_Json)))) {
+
+ //トークン取得
+ $post_json = json_decode($Get_Post_Json, true);
+ if (isset($post_json["token"])) {
+ $token = safetext($post_json["token"]);
+ } else {
+ $err = "input_not_found";
+ $response = array(
+ 'error_code' => $err,
+ 'success' => false
+ );
+ echo json_encode($response, JSON_UNESCAPED_UNICODE);
+ exit;
+ }
+
+ if ($token == "") {
+ $err = "input_not_found";
+ $response = array(
+ 'error_code' => $err,
+ 'success' => false
+ );
+ echo json_encode($response, JSON_UNESCAPED_UNICODE);
+ exit;
+ }
+
+ if(!(empty($post_json["limit"]))){
+ $limit = (int)$post_json["limit"];
+ }else{
+ $limit = 50;
+ }
+ if($limit > 500){
+ $limit = 500;
+ }
+
+ if(!(empty($post_json["page"]))){
+ $page = (int)$post_json["page"];
+ }else{
+ $page = 1;
+ }
+ $offset = ($page - 1) * $limit;
+
+ session_start();
+
+ if (!empty($pdo)) {
+ $AuthData = APIAuth($pdo, $token, "read:admin:reports");
+ if ($AuthData[0] === true && $AuthData[2]["admin"] == "yes") {
+ $sql = "SELECT * FROM report WHERE admin_chk = 'none' ORDER BY datetime DESC LIMIT :offset, :itemsPerPage";
+ $stmt = $pdo->prepare($sql);
+ $stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
+ $stmt->bindValue(':itemsPerPage', $limit, PDO::PARAM_INT);
+ $stmt->execute();
+ $allreport = $stmt;
+
+ while ($row = $allreport->fetch(PDO::FETCH_ASSOC)) {
+ $reports[] = $row;
+ }
+
+ $groupedReports = [];
+
+ if (!empty($reports)) {
+ foreach ($reports as $row) {
+ $reportedUserId = $row['userid'];
+
+ if (!isset($groupedReports[$reportedUserId])) {
+ $groupedReports[$reportedUserId] = [
+ 'reported_userid' => $reportedUserId,
+ 'total_count' => 0,
+ 'details' => []
+ ];
+ }
+ $groupedReports[$reportedUserId]['details'][] = [
+ 'uniqid' => $row['uniqid'],
+ 'reporter_userid' => $row['report_userid'],
+ 'message' => $row['msg'],
+ 'datetime' => $row['datetime']
+ ];
+
+ $groupedReports[$reportedUserId]['total_count']++;
+ }
+ }
+
+ echo json_encode([
+ 'success' => true,
+ 'data' => array_values($groupedReports)
+ ], JSON_UNESCAPED_UNICODE);
+ } else {
+ $err = $AuthData[1];
+ $response = array(
+ 'error_code' => $err,
+ 'success' => false
+ );
+
+ echo json_encode($response, JSON_UNESCAPED_UNICODE);
+ }
+ }
+} else {
+ $err = "input_not_found";
+ $response = array(
+ 'error_code' => $err,
+ 'success' => false
+ );
+
+ echo json_encode($response, JSON_UNESCAPED_UNICODE);
+}
diff --git a/api/admin/reports/resolve.php b/api/admin/reports/resolve.php
new file mode 100644
index 0000000..34d7290
--- /dev/null
+++ b/api/admin/reports/resolve.php
@@ -0,0 +1,167 @@
+ PDO::ERRMODE_EXCEPTION,
+ PDO::MYSQL_ATTR_MULTI_STATEMENTS => false
+ );
+ $pdo = new PDO('mysql:charset=utf8mb4;dbname=' . DB_NAME . ';host=' . DB_HOST, DB_USER, DB_PASS, $option);
+} catch (PDOException $e) {
+ // 接続エラーのときエラー内容を取得する
+ $error_message[] = $e->getMessage();
+}
+
+if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
+ http_response_code(405);
+ echo json_encode([
+ 'error_code' => 'method_not_allowed',
+ 'success' => false
+ ]);
+ exit;
+}
+
+$Get_Post_Json = file_get_contents("php://input");
+if ((!(empty($Get_Post_Json)))) {
+
+ //トークン取得
+ $post_json = json_decode($Get_Post_Json, true);
+ if (isset($post_json["token"])) {
+ $token = safetext($post_json["token"]);
+ } else {
+ $err = "input_not_found";
+ $response = array(
+ 'error_code' => $err,
+ 'success' => false
+ );
+ echo json_encode($response, JSON_UNESCAPED_UNICODE);
+ exit;
+ }
+
+ if ($token == "") {
+ $err = "input_not_found";
+ $response = array(
+ 'error_code' => $err,
+ 'success' => false
+ );
+ echo json_encode($response, JSON_UNESCAPED_UNICODE);
+ exit;
+ }
+
+ if(!(empty($post_json["uniqid"]))){
+ $uniqid = safetext($post_json["uniqid"]);
+ }else{
+ $uniqid = null;
+ }
+
+ if(!(empty($post_json["reported_userid"]))){
+ $reported_userid = safetext($post_json["reported_userid"]);
+ }else{
+ $reported_userid = null;
+ }
+
+ session_start();
+
+ if (!empty($pdo)) {
+ $AuthData = APIAuth($pdo, $token, "write:admin:reports");
+ if ($AuthData[0] === true && $AuthData[2]["admin"] == "yes") {
+ if(!(empty($uniqid))){
+ $newchk = "done";
+ $pdo->beginTransaction();
+ try {
+ $stmt = $pdo->prepare("UPDATE report SET admin_chk = :adchk WHERE uniqid = :uniqid");
+ $stmt->bindValue(':adchk', $newchk, PDO::PARAM_STR);
+ $stmt->bindValue(':uniqid', $uniqid, PDO::PARAM_STR);
+ $res = $stmt->execute();
+
+ if ($res) {
+ $pdo->commit();
+ $response = array(
+ 'success' => true,
+ 'uniqid' => $uniqid
+ );
+ } else {
+ $response = array(
+ 'error_code' => 'could_not_complete',
+ 'success' => false
+ );
+ $pdo->rollBack();
+ actionLog($AuthData[2]["userid"], "error", "admin-reports-resolve-api", null, "通報の解決に失敗しました", 3);
+ }
+ } catch (Exception $e) {
+ $response = array(
+ 'error_code' => 'db_error_update',
+ 'success' => false
+ );
+ $pdo->rollBack();
+ actionLog($AuthData[2]["userid"], "error", "admin-reports-resolve-api", null, $e, 4);
+ }
+ }elseif(!(empty($reported_userid))){
+ $newchk = "done";
+ $pdo->beginTransaction();
+ try {
+ $stmt = $pdo->prepare("UPDATE report SET admin_chk = :adchk WHERE userid = :userid");
+ $stmt->bindValue(':adchk', $newchk, PDO::PARAM_STR);
+ $stmt->bindValue(':userid', $reported_userid, PDO::PARAM_STR);
+ $res = $stmt->execute();
+
+ if ($res) {
+ $pdo->commit();
+ $response = array(
+ 'success' => true,
+ 'reported_userid' => $reported_userid
+ );
+ } else {
+ $response = array(
+ 'error_code' => 'could_not_complete',
+ 'success' => false
+ );
+ $pdo->rollBack();
+ actionLog($AuthData[2]["userid"], "error", "admin-reports-resolve-api", null, "通報の解決に失敗しました", 3);
+ }
+ } catch (Exception $e) {
+ $response = array(
+ 'error_code' => 'db_error_update',
+ 'success' => false
+ );
+ $pdo->rollBack();
+ actionLog($AuthData[2]["userid"], "error", "admin-reports-resolve-api", null, $e, 4);
+ }
+ }else{
+ $response = array(
+ 'error_code' => 'input_not_found',
+ 'success' => false
+ );
+ }
+ echo json_encode($response, JSON_UNESCAPED_UNICODE);
+ } else {
+ $err = $AuthData[1];
+ $response = array(
+ 'error_code' => $err,
+ 'success' => false
+ );
+
+ echo json_encode($response, JSON_UNESCAPED_UNICODE);
+ }
+ }
+} else {
+ $err = "input_not_found";
+ $response = array(
+ 'error_code' => $err,
+ 'success' => false
+ );
+
+ echo json_encode($response, JSON_UNESCAPED_UNICODE);
+}
diff --git a/api/admin/users/index.php b/api/admin/users/index.php
new file mode 100644
index 0000000..4df473b
--- /dev/null
+++ b/api/admin/users/index.php
@@ -0,0 +1,265 @@
+ PDO::ERRMODE_EXCEPTION,
+ PDO::MYSQL_ATTR_MULTI_STATEMENTS => false
+ );
+ $pdo = new PDO('mysql:charset=utf8mb4;dbname=' . DB_NAME . ';host=' . DB_HOST, DB_USER, DB_PASS, $option);
+} catch (PDOException $e) {
+ // 接続エラーのときエラー内容を取得する
+ $error_message[] = $e->getMessage();
+}
+
+
+if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
+ http_response_code(405);
+ echo json_encode([
+ 'error_code' => 'method_not_allowed',
+ 'success' => false
+ ]);
+ exit;
+}
+
+$Get_Post_Json = file_get_contents("php://input");
+if ((!(empty($Get_Post_Json)))) {
+
+ //トークン取得
+ $post_json = json_decode($Get_Post_Json, true);
+ if (isset($post_json["token"])) {
+ $token = safetext($post_json["token"]);
+ } else {
+ $err = "input_not_found";
+ $response = array(
+ 'error_code' => $err,
+ 'success' => false
+ );
+ echo json_encode($response, JSON_UNESCAPED_UNICODE);
+ exit;
+ }
+
+ if ($token == "") {
+ $err = "input_not_found";
+ $response = array(
+ 'error_code' => $err,
+ 'success' => false
+ );
+ echo json_encode($response, JSON_UNESCAPED_UNICODE);
+ exit;
+ }
+
+ if(!(empty($post_json["userid"]))) {
+ $userid = safetext($post_json["userid"]);
+ } else {
+ $err = "input_not_found";
+ $response = array(
+ 'error_code' => $err,
+ 'success' => false
+ );
+
+ echo json_encode($response, JSON_UNESCAPED_UNICODE);
+ exit;
+ }
+
+ session_start();
+
+ if (!empty($pdo)) {
+ $AuthData = APIAuth($pdo, $token, "read:admin:users");
+ if ($AuthData[0] === true && $AuthData[2]["admin"] == "yes") {
+ $userdata = getUserData($pdo, $userid);
+
+ if (empty($userdata)) {
+ $response = array(
+ 'error_code' => "critical_error_userdata_not_found",
+ );
+ } else {
+ $roles = explode(',', $userdata["role"]);
+ if (!(empty($roles))) {
+ foreach ($roles as $roleId) {
+ $Getrole = $pdo->prepare("SELECT roleidname, rolename, roleauth, rolecolor, roleeffect FROM role WHERE roleidname = :role");
+ $Getrole->bindValue(':role', $roleId);
+ $Getrole->execute();
+ $roleData[$roleId] = $Getrole->fetch();
+
+ if ($roleData[$roleId]['roleeffect'] == '' || $roleData[$roleId]['roleeffect'] == 'none') {
+ $role_view_effect = "none";
+ } elseif ($roleData[$roleId]['roleeffect'] == 'shine') {
+ $role_view_effect = "shine";
+ } elseif ($roleData[$roleId]['roleeffect'] == 'rainbow') {
+ $role_view_effect = "rainbow";
+ } else {
+ $role_view_effect = "none";
+ }
+
+ $roleinfo = array(
+ "name" => decode_yajirushi(htmlspecialchars_decode($roleData[$roleId]['rolename'])),
+ "color" => decode_yajirushi(htmlspecialchars_decode($roleData[$roleId]['rolecolor'])),
+ "effect" => decode_yajirushi(htmlspecialchars_decode($role_view_effect)),
+ "id" => decode_yajirushi(htmlspecialchars_decode($roleData[$roleId]['roleidname'])),
+ );
+
+ $role[] = $roleinfo;
+ }
+ } else {
+ $role[] = "";
+ }
+
+ if (!(empty($userdata["sacinfo"]))) {
+ if ($userdata["sacinfo"] == "bot") {
+ $isBot = true;
+ } else {
+ $isBot = false;
+ }
+ } else {
+ $isBot = false;
+ }
+
+ if (!(empty($userdata["admin"]))) {
+ if ($userdata["admin"] == "yes") {
+ $isAdmin = true;
+ } else {
+ $isAdmin = false;
+ }
+ } else {
+ $isAdmin = false;
+ }
+
+ $isPublicOnlineStatus = val_OtherSettings("isPublicOnlineStatus", $userdata["other_settings"]);
+ if ($isPublicOnlineStatus === true) {
+ if (!(empty($userdata["last_login_datetime"]))) {
+ $lastLogin = new DateTime($userdata["last_login_datetime"]);
+ $now = new DateTime();
+
+ $interval = $now->diff($lastLogin);
+
+ $minutesPast = ($interval->days * 24 * 60) + ($interval->h * 60) + $interval->i;
+
+ $status_datetime = $userdata["last_login_datetime"];
+
+ if ($minutesPast <= 5) {
+ $online_status = "Online";
+ $real_online_status = "Online";
+ } elseif ($minutesPast <= 15) {
+ $online_status = "Away";
+ $real_online_status = "Away";
+ } else {
+ $online_status = "Offline";
+ $real_online_status = "Offline";
+ }
+ } else {
+ $online_status = "Offline";
+ $real_online_status = "Offline";
+ }
+ } else {
+ $online_status = null;
+ if (!(empty($userdata["last_login_datetime"]))) {
+ $lastLogin = new DateTime($userdata["last_login_datetime"]);
+ $now = new DateTime();
+
+ $interval = $now->diff($lastLogin);
+
+ $minutesPast = ($interval->days * 24 * 60) + ($interval->h * 60) + $interval->i;
+
+ $status_datetime = $userdata["last_login_datetime"];
+
+ if ($minutesPast <= 5) {
+ $real_online_status = "Online";
+ } elseif ($minutesPast <= 15) {
+ $real_online_status = "Away";
+ } else {
+ $real_online_status = "Offline";
+ }
+ } else {
+ $real_online_status = "Offline";
+ }
+ }
+
+ $followee = getFolloweeList($pdo, $userdata["userid"]);
+ if ($followee === false) {
+ $followee = array();
+ }
+ $follower = getFollowerList($pdo, $userdata["userid"]);
+ if ($follower === false) {
+ $follower = array();
+ }
+
+ $userdata["follow_cnt"] = (int)count($followee);
+ $userdata["follower_cnt"] = (int)count($follower);
+
+ $allueuse = $pdo->prepare("SELECT account FROM ueuse WHERE account = :userid");
+ $allueuse->bindValue(':userid', $userdata["userid"]);
+ $allueuse->execute();
+ $All_ueuse = $allueuse->rowCount();
+
+ if (!(empty($userdata["encryption_ivkey"]))) {
+ $view_mailadds = DecryptionUseEncrKey($userdata["mailadds"], GenUserEnckey($userdata["datetime"]), $userdata["encryption_ivkey"]);
+ $view_ip_addr = DecryptionUseEncrKey($userdata["last_ip"], GenUserEnckey($userdata["datetime"]), $userdata["encryption_ivkey"]);
+ } else {
+ $view_mailadds = $userdata["mailadds"];
+ $view_ip_addr = $userdata["last_ip"];
+ }
+
+ if (!empty($userdata["authcode"])) {
+ $is_2fa_configured = true;
+ } else {
+ $is_2fa_configured = false;
+ }
+
+ $response = array(
+ 'success' => true,
+ 'username' => decode_yajirushi(htmlspecialchars_decode($userdata["username"])),
+ 'userid' => decode_yajirushi(htmlspecialchars_decode($userdata["userid"])),
+ 'profile' => decode_yajirushi(htmlspecialchars_decode($userdata["profile"])),
+ 'user_icon' => decode_yajirushi(htmlspecialchars_decode(localcloudURLtoAPI(localcloudURL($userdata["iconname"])))),
+ 'user_header' => decode_yajirushi(htmlspecialchars_decode(localcloudURLtoAPI(localcloudURL($userdata["headname"])))),
+ 'registered_date' => decode_yajirushi(htmlspecialchars_decode($userdata["datetime"])),
+ 'followee' => $followee,
+ 'followee_cnt' => $userdata["follow_cnt"],
+ 'follower' => $follower,
+ 'follower_cnt' => $userdata["follower_cnt"],
+ 'ueuse_cnt' => $All_ueuse,
+ 'isBot' => $isBot,
+ 'isAdmin' => $isAdmin,
+ 'role' => $role,
+ 'online_status' => $online_status,
+ 'real_online_status' => $real_online_status,
+ 'last_login_datetime' => $userdata["last_login_datetime"],
+ 'last_login_ipaddress' => $view_ip_addr,
+ 'mailaddress' => $view_mailadds,
+ 'is_2fa_configured' => $is_2fa_configured,
+ 'language' => "ja-JP",
+ );
+ }
+ echo json_encode($response, JSON_UNESCAPED_UNICODE);
+ } else {
+ $err = $AuthData[1];
+ $response = array(
+ 'error_code' => $err,
+ 'success' => false
+ );
+
+ echo json_encode($response, JSON_UNESCAPED_UNICODE);
+ }
+ }
+} else {
+ $err = "input_not_found";
+ $response = array(
+ 'error_code' => $err,
+ 'success' => false
+ );
+
+ echo json_encode($response, JSON_UNESCAPED_UNICODE);
+}
diff --git a/api/admin/users/sanction.php b/api/admin/users/sanction.php
new file mode 100644
index 0000000..5f9e246
--- /dev/null
+++ b/api/admin/users/sanction.php
@@ -0,0 +1,409 @@
+ PDO::ERRMODE_EXCEPTION,
+ PDO::MYSQL_ATTR_MULTI_STATEMENTS => false
+ );
+ $pdo = new PDO('mysql:charset=utf8mb4;dbname=' . DB_NAME . ';host=' . DB_HOST, DB_USER, DB_PASS, $option);
+} catch (PDOException $e) {
+ // 接続エラーのときエラー内容を取得する
+ $error_message[] = $e->getMessage();
+}
+
+if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
+ http_response_code(405);
+ echo json_encode([
+ 'error_code' => 'method_not_allowed',
+ 'success' => false
+ ]);
+ exit;
+}
+
+$Get_Post_Json = file_get_contents("php://input");
+if ((!(empty($Get_Post_Json)))) {
+ //トークン取得
+ $post_json = json_decode($Get_Post_Json, true);
+ if (isset($post_json["token"])) {
+ $token = safetext($post_json["token"]);
+ } else {
+ $err = "input_not_found";
+ $response = array(
+ 'error_code' => $err,
+ 'success' => false
+ );
+ echo json_encode($response, JSON_UNESCAPED_UNICODE);
+ exit;
+ }
+
+ if ($token == "") {
+ $err = "input_not_found";
+ $response = array(
+ 'error_code' => $err,
+ 'success' => false
+ );
+ echo json_encode($response, JSON_UNESCAPED_UNICODE);
+ exit;
+ }
+
+ if (!(empty($post_json["userid"]))) {
+ $userid = safetext($post_json["userid"]);
+ } else {
+ $err = "input_not_found";
+ $response = array(
+ 'error_code' => $err,
+ 'success' => false
+ );
+
+ echo json_encode($response, JSON_UNESCAPED_UNICODE);
+ exit;
+ }
+
+ if (!(empty($post_json["type"]))) {
+ $type = safetext($post_json["type"]);
+ } else {
+ $err = "input_not_found";
+ $response = array(
+ 'error_code' => $err,
+ 'success' => false
+ );
+ echo json_encode($response, JSON_UNESCAPED_UNICODE);
+ exit;
+ }
+
+ session_start();
+
+ if (!empty($pdo)) {
+ $AuthData = APIAuth($pdo, $token, "write:admin:user-sanction");
+ if ($AuthData[0] === true && $AuthData[2]["admin"] == "yes") {
+ $userdata = getUserData($pdo, $userid);
+
+ if (empty($userdata)) {
+ $response = array(
+ 'error_code' => "critical_error_userdata_not_found",
+ );
+ } else {
+ if (!(empty($userdata["encryption_ivkey"]))) {
+ $view_mailadds = DecryptionUseEncrKey($userdata["mailadds"], GenUserEnckey($userdata["datetime"]), $userdata["encryption_ivkey"]);
+ $view_ip_addr = DecryptionUseEncrKey($userdata["last_ip"], GenUserEnckey($userdata["datetime"]), $userdata["encryption_ivkey"]);
+ } else {
+ $view_mailadds = $userdata["mailadds"];
+ $view_ip_addr = $userdata["last_ip"];
+ }
+
+ if ($type == "notification") {
+ if (!(empty($post_json["notification_title"]))) {
+ $notice_title = safetext($post_json["notification_title"]);
+ } else {
+ $err = "input_not_found";
+ }
+
+ if (!(empty($post_json["notification_message"]))) {
+ $notice_msg = safetext($post_json["notification_message"]);
+ } else {
+ $err = "input_not_found";
+ }
+
+ if (empty($notice_title)) {
+ $err = "input_not_found";
+ } elseif (mb_strlen($notice_title) > 512) {
+ $err = "content_to_512_characters";
+ }
+ if (empty($notice_msg)) {
+ $err = "input_not_found";
+ } elseif (mb_strlen($notice_msg) > 16777216) {
+ $err = "content_to_16777216_characters";
+ }
+ if (empty($err)) {
+ $url = safetext("/rule/serverabout");
+ $response = send_notification($userdata['userid'], "uwuzu-fromsys", $notice_title, $notice_msg, $url, "system");
+ if ($response == true) {
+ actionLog($AuthData[2]["userid"], "info", "admin-user-sanction-api-send_notification", $userdata['userid'], $userdata['userid'] . "さんに" . $AuthData[2]["userid"] . "さんが通知を送信しました。\n" . $notice_msg, 0);
+ $response = array(
+ 'success' => true,
+ 'userid' => $userdata['userid']
+ );
+ } else {
+ actionLog($AuthData[2]["userid"], "error", "admin-user-sanction-api-send_notification", $userdata['userid'], $userdata['userid'] . "さんに" . $AuthData[2]["userid"] . "さんが通知を送信できませんでした。\n" . $notice_msg, 4);
+ $response = array(
+ 'error_code' => "could_not_complete",
+ 'success' => false
+ );
+ }
+ } else {
+ $response = array(
+ 'error_code' => $err,
+ 'success' => false
+ );
+ }
+ } elseif ($type == "frozen") {
+ if(!($userdata["role"] === "ice")){
+ if (!(empty($post_json["notification_message"]))) {
+ $notice_msg = safetext($post_json["notification_message"]);
+ } else {
+ $err = "input_not_found";
+ }
+
+ // --- バリデーション ---
+ if (empty($notice_msg)) {
+ $err = "input_not_found";
+ } elseif (mb_strlen($notice_msg) > 16777216) {
+ $err = "content_to_16777216_characters";
+ }
+
+ if (empty($err)) {
+ $touserid = $userdata['userid'];
+ $newrole = "ice";
+ $newtoken = "ice";
+ $newadmin = "none";
+
+ $pdo->beginTransaction();
+ try {
+ $stmt = $pdo->prepare("UPDATE account SET role = :role, token = :newtoken, admin = :newadmin WHERE userid = :userid");
+ $stmt->bindValue(':role', $newrole, PDO::PARAM_STR);
+ $stmt->bindValue(':newtoken', $newtoken, PDO::PARAM_STR);
+ $stmt->bindValue(':newadmin', $newadmin, PDO::PARAM_STR);
+ $stmt->bindValue(':userid', $touserid, PDO::PARAM_STR);
+ $stmt->execute();
+ $pdo->commit();
+ $account_updated = true;
+ } catch (Exception $e) {
+ $pdo->rollBack();
+ $account_updated = false;
+ $err_msg = $e->getMessage();
+ }
+
+ if ($account_updated) {
+ $notice_title = "🧊お使いのアカウントは凍結されました。🧊";
+ $full_msg = "サービス管理者からのメッセージは以下のものです。\n" . $notice_msg . "\n異議申し立てする場合は連絡用メールに異議申し立てをする旨を記載し送信をしてください。";
+ $url = safetext("/rule/serverabout");
+
+ $notif_res = send_notification($touserid, "uwuzu-fromsys", $notice_title, $full_msg, $url, "system");
+
+ if (false !== strpos($userdata["mail_settings"], 'important')) {
+ if (!empty(MAIL_CHKS) && MAIL_CHKS == "true") {
+ if (!empty($view_mailadds) && filter_var($view_mailadds, FILTER_VALIDATE_EMAIL)) {
+ $mail_title = "お使いの" . safetext($serversettings["serverinfo"]["server_name"]) . "アカウントは凍結されました";
+ $mail_text = "".$userdata["username"]."(".$userdata["userid"].")さん いつもuwuzuをご利用いただきありがとうございます。 ご利用のアカウント(".$userdata["userid"].")が".safetext($serversettings["serverinfo"]["server_name"])."管理者により凍結されたためお知らせいたします。 サービス管理者からのメッセージは以下のものです。 ". safetext($notice_msg) ." 異議申し立てする場合は[".safetext($serversettings["serverinfo"]["server_admin_mailadds"])."]まで異議申し立てをする旨を記載し送信をしてください。";
+ $sendmail_error_message[] = send_html_mail($view_mailadds, $mail_title, $mail_text, "../../../");
+ if(!(empty($sendmail_error_message))){
+ actionLog($AuthData[2]["userid"], "error", "admin-user-sanction-api-frozen", $userdata['userid'], $sendmail_error_message, 3);
+ }
+ }
+ }
+ }
+
+ actionLog($AuthData[2]["userid"], "info", "admin-user-sanction-api-frozen", $touserid, $touserid . "さんを" . $AuthData[2]["userid"] . "さんが凍結しました。\n理由: " . $notice_msg, 0);
+ $response = array(
+ 'success' => true,
+ 'userid' => $touserid
+ );
+ } else {
+ actionLog($AuthData[2]["userid"], "error", "admin-user-sanction-api-frozen", $touserid, $err_msg, 4);
+ $response = array(
+ 'error_code' => "could_not_complete",
+ 'success' => false
+ );
+ }
+ } else {
+ $response = array(
+ 'error_code' => $err,
+ 'success' => false
+ );
+ }
+ }else{
+ $response = array(
+ 'error_code' => "already_been_completed",
+ 'success' => false
+ );
+ }
+ } elseif ($type == "unfrozen") {
+ if($userdata["role"] === "ice"){
+ $touserid = $userdata['userid'];
+ $newrole = "user";
+ $newtoken = "";
+ $newadmin = "none";
+
+ $pdo->beginTransaction();
+ try {
+ $stmt = $pdo->prepare("UPDATE account SET role = :role, token = :newtoken, admin = :newadmin WHERE userid = :userid");
+ $stmt->bindValue(':role', $newrole, PDO::PARAM_STR);
+ $stmt->bindValue(':newtoken', $newtoken, PDO::PARAM_STR);
+ $stmt->bindValue(':newadmin', $newadmin, PDO::PARAM_STR);
+ $stmt->bindValue(':userid', $touserid, PDO::PARAM_STR);
+ $stmt->execute();
+
+ $pdo->commit();
+ $account_updated = true;
+ } catch (Exception $e) {
+ $pdo->rollBack();
+ $account_updated = false;
+ $err_msg = $e->getMessage();
+ }
+
+ if ($account_updated) {
+ $notice_title = "🫗お使いのアカウントが解凍されました!🫗";
+ $full_msg = "サービス管理者によりお使いのアカウントは解凍されました!\n今まで通りご利用いただけます。";
+ $url = safetext("/home");
+
+ $notif_res = send_notification($touserid, "uwuzu-fromsys", $notice_title, $full_msg, $url, "system");
+
+ if (false !== strpos($userdata["mail_settings"], 'important')) {
+ if (!empty(MAIL_CHKS) && MAIL_CHKS == "true") {
+ if (!empty($view_mailadds) && filter_var($view_mailadds, FILTER_VALIDATE_EMAIL)) {
+ $mail_title = "お使いの" . safetext($serversettings["serverinfo"]["server_name"]) . "アカウントは解凍されました!";
+ $mail_text = "".$userdata["username"]."(".$userdata["userid"].")さん いつもuwuzuをご利用いただきありがとうございます。 ご利用のアカウント(".$userdata["userid"].")が解凍されたためお知らせいたします。 今後、ご利用のuwuzuアカウントは今まで通りご利用いただけます。";
+
+ $sendmail_error_message[] = send_html_mail($view_mailadds, $mail_title, $mail_text, "../../../");
+ if(!(empty($sendmail_error_message))){
+ actionLog($AuthData[2]["userid"], "error", "admin-user-sanction-api-unfrozen", $userdata['userid'], $sendmail_error_message, 3);
+ }
+ }
+ }
+ }
+
+ actionLog($AuthData[2]["userid"], "info", "admin-user-sanction-api-unfrozen", $touserid, $touserid . "さんを" . $AuthData[2]["userid"] . "さんが解凍しました", 0);
+
+ $response = array(
+ 'success' => true,
+ 'userid' => $touserid
+ );
+ } else {
+ actionLog($AuthData[2]["userid"], "error", "admin-user-sanction-api-unfrozen", $touserid, $err_msg, 4);
+ $response = array(
+ 'error_code' => "could_not_complete",
+ 'success' => false
+ );
+ }
+ }else{
+ $response = array(
+ 'error_code' => "already_been_completed",
+ 'success' => false
+ );
+ }
+ } elseif ($type == "ban") {
+ if($userdata["role"] === "ice"){
+ if (!(empty($post_json["really"]))) {
+ $really = safetext($post_json["really"]);
+ } else {
+ $err = "input_not_found";
+ }
+
+ if (empty($really)) {
+ $err = "input_not_found";
+ }else{
+ if(!(empty($AuthData[2]["authcode"]))){
+ if(!(empty($AuthData[2]["encryption_ivkey"])) && (!(mb_strlen($AuthData[2]["authcode"]) === 16))){
+ $private_authcode = DecryptionUseEncrKey($AuthData[2]["authcode"], GenUserEnckey($AuthData[2]["datetime"]), $AuthData[2]["encryption_ivkey"]);
+ }else{
+ $private_authcode = $AuthData[2]["authcode"];
+ }
+
+ $chkauthcode = new PHPGangsta_GoogleAuthenticator();
+ $checkResult = $chkauthcode->verifyCode($private_authcode, $really, 2);
+ if ($checkResult == false) {
+ $err = "input_not_found";
+ }
+ }else{
+ if(!($really === "yes_i_will_delete_".safetext($userdata["userid"]))){
+ $err = "input_not_found";
+ }
+ }
+ }
+
+ if (empty($err)) {
+ try{
+ $res = addJob($pdo, $userdata['userid'], "deleteUser", "stop_account");
+
+ if ($res) {
+ actionLog($AuthData[2]["userid"], "info", "admin-user-sanction-api-ban", $userdata['userid'], $AuthData[2]["userid"]."さんが".$userdata['userid']."さんをBANしました", 4);
+ $response = array(
+ 'success' => true,
+ 'userid' => $userdata['userid']
+ );
+ //BAN通知メール
+ if(false !== strpos($userdata["mail_settings"], 'important')) {
+ if(!empty(MAIL_CHKS)){
+ if(MAIL_CHKS == "true"){
+ if( !empty($view_mailadds) ){
+ if(filter_var($view_mailadds, FILTER_VALIDATE_EMAIL)){
+ $mail_title = "お使いの".safetext($serversettings["serverinfo"]["server_name"])."アカウントはBANされました";
+ $mail_text = "".$userdata["username"]."(".$userdata["userid"].")さん いつもuwuzuをご利用いただきありがとうございます。 この度、ご利用のアカウント(".$userdata["userid"].")が".safetext($serversettings["serverinfo"]["server_name"])."管理者によりBAN(削除)されたためお知らせいたします。 今後は今までご利用いただいた".safetext($serversettings["serverinfo"]["server_name"])."アカウントは利用できません。 ".safetext($serversettings["serverinfo"]["server_name"])."サーバー上から今までご利用いただいていたアカウントの情報は削除されたためログインなどもできません。 ご理解とご協力のほどよろしくお願いします。";
+
+ $error_message[] = send_html_mail($view_mailadds,$mail_title,$mail_text,"../../../");
+ }
+ }
+ }
+ }
+ }
+ //------------
+ } else {
+ $error_message[] = 'アカウント削除に失敗しました。(ACCOUNT_DELETE_DAME)';
+ actionLog($AuthData[2]["userid"], "error", "admin-user-sanction-api-ban", $userdata['userid'], $error_message[], 4);
+ }
+ } catch (Exception $e) {
+ $pdo->rollBack();
+ actionLog($AuthData[2]["userid"], "error", "admin-user-sanction-api-ban", $userdata['userid'], $e, 4);
+ }
+ }else{
+ $response = array(
+ 'error_code' => $err,
+ 'success' => false
+ );
+ }
+ }else{
+ $response = array(
+ 'error_code' => "user_not_frozen_cant_be_banned",
+ 'success' => false
+ );
+ }
+ } else {
+ $response = array(
+ 'error_code' => "input_not_found",
+ 'success' => false
+ );
+ }
+ }
+ echo json_encode($response, JSON_UNESCAPED_UNICODE);
+ } else {
+ $err = $AuthData[1];
+ $response = array(
+ 'error_code' => $err,
+ 'success' => false
+ );
+
+ echo json_encode($response, JSON_UNESCAPED_UNICODE);
+ }
+ }
+} else {
+ $err = "input_not_found";
+ $response = array(
+ 'error_code' => $err,
+ 'success' => false
+ );
+
+ echo json_encode($response, JSON_UNESCAPED_UNICODE);
+}
diff --git a/api/auth.php b/api/auth.php
index 039386b..5351ddb 100644
--- a/api/auth.php
+++ b/api/auth.php
@@ -96,6 +96,13 @@ $is_trueclient = false;
if(!(empty($_GET["session"])) && !(empty($_GET["client"])) && !(empty($_GET["scope"]))){
$is_trueclient = true;
$session_code = safetext($_GET["session"]);
+
+ if($is_Admin == "yes"){
+ $admin_permission = true;
+ }else{
+ $admin_permission = false;
+ }
+
if(strlen($session_code) > 512){
$is_trueclient = false;
}
@@ -114,8 +121,8 @@ if(!(empty($_GET["session"])) && !(empty($_GET["client"])) && !(empty($_GET["sco
$securityScopesView = false;
foreach ($client_scope_base as $scope) {
- if (GetAPIScopes($scope)) {
- $client_scope[] = GetAPIScopes($scope);
+ if (GetAPIScopes($scope, $admin_permission)) {
+ $client_scope[] = GetAPIScopes($scope, $admin_permission);
if($securityScopesView === false && in_array($scope, $securityScopes)){
$securityScopesView = true;
}
@@ -156,7 +163,7 @@ if($is_trueclient === true){
}
foreach ($client_scope_base as $scope) {
- if (GetAPIScopes($scope)) {
+ if (GetAPIScopes($scope, $admin_permission)) {
$client_scope_done[] = $scope;
}else{
$client_scope_done = array();
@@ -196,6 +203,10 @@ if($is_trueclient === true){
$pdo->rollBack();
}
if($res) {
+ if($admin_permission === true){
+ actionLog($userid, "info", "api/auth", $client_name, "管理者のアカウントでAPIトークンが発行されました。\n".$client_scope_done, 4);
+ }
+
if(!(empty($client_callback))){
header("Location: ".$client_callback."");
exit;
diff --git a/bookmark/index.php b/bookmark/index.php
index f9daedd..4348c31 100644
--- a/bookmark/index.php
+++ b/bookmark/index.php
@@ -206,6 +206,7 @@ $pdo = null;
![]()
+
diff --git a/css/home.css b/css/home.css
index 94f5972..01ade5f 100644
--- a/css/home.css
+++ b/css/home.css
@@ -16,12 +16,12 @@
background: var(--main-color);
}
-.flexbox{
+.flexbox {
display: flex;
-
+
}
-.btnbox{
+.btnbox {
width: auto;
margin: 0px auto;
}
@@ -176,7 +176,8 @@ textarea {
line-height: 20px;
border: 1px solid var(--error);
}
-.justfit{
+
+.justfit {
margin: 16px 0px;
}
@@ -588,7 +589,6 @@ main h1 {
width: 148px;
height: 148px;
border-radius: 50%;
- box-shadow: 0 0px 48px 0 rgba(0, 0, 0, .05);
}
.userheader .icon h2 img {
@@ -602,6 +602,29 @@ main h1 {
border-radius: 0px;
}
+.userheader .icon .status {
+ position: relative;
+ left: calc(-24px + -8px);
+ top: calc(32px - 4px);
+ width: 24px;
+ height: 24px;
+ border-radius: 50%;
+ background-color: #CCC;
+ border: solid 4px var(--tl-color);
+}
+
+.userheader .icon .green {
+ background-color: #00cc4e;
+}
+
+.userheader .icon .yellow {
+ background-color: #ffc400;
+}
+
+.userheader .icon .gray {
+ background-color: #CCC;
+}
+
.userheader h2 {
word-wrap: break-word;
margin-left: 12px;
@@ -1257,6 +1280,7 @@ main h1 {
transition: 0.5s;
opacity: 0;
}
+
.ueuse .blur:hover * {
opacity: 1;
}
@@ -2436,7 +2460,7 @@ main h1 {
margin-top: auto;
margin-bottom: auto;
margin-left: 6px;
- border-radius: 6px;
+ border-radius: 16px;
background-color: var(--background-color);
border: 1px solid var(--border-color);
}
@@ -2444,8 +2468,8 @@ main h1 {
.ueuse .reuse_box .reuse_flebox .idbox a {
margin-top: 3px;
margin-bottom: 3px;
- margin-left: 4px;
- margin-right: 4px;
+ margin-left: 8px;
+ margin-right: 8px;
text-align: center;
font-size: 12px;
text-decoration: none;
@@ -2852,6 +2876,85 @@ main h1 {
font-weight: normal;
}
+/*
+.sendbox #preview_container {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 10px;
+ margin-bottom: 10px;
+}
+
+.sendbox .preview-item {
+ background: linear-gradient(45deg, #CCC 25%, transparent 25%, transparent 75%, #CCC 75%),
+ linear-gradient(45deg, #CCC 25%, transparent 25%, transparent 75%, #CCC 75%);
+ background-color: #FFF;
+ background-size: 20px 20px;
+ background-position: 0 0, 10px 10px;
+
+ border: 1px solid #ccc;
+ position: relative;
+ border-radius: 10px;
+ overflow: hidden;
+}
+
+.sendbox .img-preview img {
+ width: 96px;
+ height: 96px;
+ object-fit: cover;
+ display: block;
+}
+
+.sendbox .video-preview {
+ width: 128px;
+ height: 96px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ color: white;
+}
+.sendbox .video-preview img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+}
+.sendbox .video-preview.simple {
+ background: #333;
+}
+.sendbox .video-preview.simple .video-label {
+ font-size: 16px;
+ margin-bottom: 4px;
+}
+.sendbox .video-preview.simple .video-size {
+ font-size: 12px;
+ color: #aaa;
+}
+
+.sendbox .remove-preview {
+ opacity: 0.5;
+ position: absolute;
+ top: 4px;
+ right: 4px;
+ background-color: #000;
+ color: #FFF;
+ border-radius: 50%;
+ width: 24px;
+ height: 24px;
+ line-height: 22px;
+ text-align: center;
+ cursor: pointer;
+ font-weight: bold;
+ z-index: 10;
+ transition: all ease-out 250ms;
+ border: solid 1px transparent;
+}
+.sendbox .remove-preview:hover {
+ opacity: 1;
+ background-color: var(--error);
+ border: solid 1px #FFF;
+}
+*/
+
.ueusebtn {
cursor: pointer;
border: none;
@@ -3535,7 +3638,7 @@ label>input {
animation: SlideDown .15s ease-in-out forwards;
}
-.modal-content .scope_desc{
+.modal-content .scope_desc {
margin-left: 8px;
line-height: 24px;
overflow-wrap: break-word;
@@ -3579,6 +3682,18 @@ label>input {
margin-bottom: 16px;
}
+.Image_modal {
+ display: none;
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-color: rgba(0, 0, 0, 0.25);
+ backdrop-filter: blur(5px);
+ z-index: 9999;
+ transition: all 250ms ease-out;
+}
.Image_modal {
display: none;
position: fixed;
@@ -3608,21 +3723,45 @@ label>input {
box-shadow: 0 0px 48px 0 rgba(0, 0, 0, .15);
overflow: hidden;
cursor: zoom-out;
+ background-color: #fff;
+
+ display: flex;
+ flex-direction: column;
}
.Image_modal .modal-content img {
- background: linear-gradient(45deg, #CCC 25%, transparent 25%, transparent 75%, #CCC 75%),
- linear-gradient(45deg, #CCC 25%, transparent 25%, transparent 75%, #CCC 75%);
+ background: linear-gradient(45deg, #CCC 25%, transparent 25%, transparent 75%, #CCC 75%), linear-gradient(45deg, #CCC 25%, transparent 25%, transparent 75%, #CCC 75%);
background-color: #FFF;
background-size: 20px 20px;
background-position: 0 0, 10px 10px;
width: 100%;
- height: 80dvh;
+ max-height: 80dvh;
margin: 0px;
vertical-align: top;
object-fit: contain;
}
+.warning-footer {
+ padding: 4px 20px;
+ background-color: var(--error);
+ color: var(--dark-text-color);
+ line-height: 22px;
+ font-size: 16px;
+ font-family: var(--Text-fonts);
+ font-weight: bold;
+ text-align: center;
+ border-top: 1px solid #FFFFFF;
+ font-weight: bold;
+ display: none;
+}
+.warning-footer span{
+ margin-right: 16px;
+ color: var(--dark-text-color);
+ font-size: 18px;
+ font-family: var(--Mono-fonts);
+ font-weight: bold;
+}
+
.topbox {
position: fixed;
@@ -4550,10 +4689,12 @@ label>input {
background-color: var(--notification-color);
color: var(--text-color);
}
+
.notification .blur * {
transition: 0.5s;
opacity: 0;
}
+
.notification .blur:hover * {
opacity: 1;
}
@@ -4992,6 +5133,45 @@ hr {
margin-bottom: 6px;
}
+.hny .done_button {
+ cursor: pointer;
+ border: none;
+ display: block;
+ width: 20%;
+ padding: 8px auto;
+ margin-left: auto;
+ margin-right: 0px;
+
+ padding-top: 6px;
+ padding-bottom: 6px;
+
+
+ background-color: var(--main-color);
+
+ border-radius: 50px;
+ color: var(--sub-color);
+ font-size: 16px;
+ font-family: var(--Head-fonts), sans-serif;
+ font-weight: normal;
+ text-decoration: none;
+ text-align: center;
+ transition: box-shadow 250ms ease-in-out;
+ transition: width 250ms ease-out;
+ transition: all 250ms ease-out;
+}
+
+.hny .done_button:hover {
+ background-color: var(--main-color);
+ color: var(--sub-color);
+ box-shadow: 0 0px 48px 0 rgba(0, 0, 0, .2);
+ width: 21%;
+}
+
+.hny .done_button:active {
+ box-shadow: 0 0px 48px 0 rgba(0, 0, 0, .0);
+ width: 19%;
+}
+
.switch_input {
position: absolute;
width: 50px;
@@ -5146,14 +5326,14 @@ summary {
list-style: none;
}
-.report_summary{
- display:flex;
- justify-content:space-between;
- align-items:center;
- width:100%;
+.report_summary {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ width: 100%;
}
-.report_summary .count{
+.report_summary .count {
font-size: 16px;
color: var(--subtext-color);
padding: 2px 8px;
@@ -5170,7 +5350,8 @@ summary {
padding-bottom: 0px;
border-radius: 8px;
}
-.report-entry .p2{
+
+.report-entry .p2 {
margin: 0px;
}
@@ -5388,6 +5569,44 @@ summary {
font-weight: 900;
}
+.admin_userinfo .icon .tatext .status {
+ display: flex;
+ vertical-align: top;
+ margin-left: 12px;
+ margin-right: auto;
+ margin-top: auto;
+ margin-bottom: 0px;
+}
+
+.admin_userinfo .icon .tatext .status p {
+ margin: 2px 0px 0px 8px;
+ vertical-align: middle;
+ line-height: 14px;
+ color: var(--subtext-color);
+ font-size: 14px;
+ font-family: var(--Mono-fonts), sans-serif;
+}
+
+.admin_userinfo .icon .tatext .circle {
+ width: 16px;
+ height: 16px;
+ border-radius: 50%;
+ background-color: #CCC;
+}
+
+.admin_userinfo .icon .tatext .green {
+ background-color: #00cc4e;
+}
+
+.admin_userinfo .icon .tatext .yellow {
+ background-color: #ffc400;
+}
+
+.admin_userinfo .icon .tatext .gray {
+ background-color: #CCC;
+}
+
+
.admin_userinfo .profile p {
text-align: left;
margin-top: 12px;
@@ -6387,26 +6606,29 @@ noscript .noscript_modal .inner .center_text p {
font-weight: normal;
}
-.auth_clientbox{
+.auth_clientbox {
width: 100%;
height: fit-content;
background-color: var(--background-color);
border: solid 1px var(--border-color);
border-radius: 10px;
}
-.auth_clientbox .flexbox{
+
+.auth_clientbox .flexbox {
margin: 16px;
display: flex;
width: 100%;
height: fit-content;
}
-.auth_clientbox .flexbox img{
+
+.auth_clientbox .flexbox img {
width: 64px;
height: 64px;
object-fit: cover;
border-radius: 8px;
}
-.auth_clientbox .flexbox p{
+
+.auth_clientbox .flexbox p {
width: calc(100% - 24px);
margin: auto auto auto 16px;
font-weight: bold;
@@ -6414,35 +6636,41 @@ noscript .noscript_modal .inner .center_text p {
line-height: 24px;
color: var(--text-color);
}
-.auth_clientbox .about{
+
+.auth_clientbox .about {
margin: 16px;
width: calc(100% - 32px);
}
-.auth_clientbox .about .scopebox{
+
+.auth_clientbox .about .scopebox {
width: calc(100% - 32px);
border: solid 1px var(--border-color);
background-color: var(--tl-color);
border-radius: 8px;
padding: 2px 16px;
}
-.auth_clientbox .accountbox{
+
+.auth_clientbox .accountbox {
width: calc(100% - 32px);
height: fit-content;
margin: 16px;
}
-.auth_clientbox .accountbox .flexbox{
+
+.auth_clientbox .accountbox .flexbox {
margin: 0px;
display: flex;
width: 100%;
height: fit-content;
}
-.auth_clientbox .accountbox .flexbox img{
+
+.auth_clientbox .accountbox .flexbox img {
width: 32px;
height: 32px;
object-fit: cover;
border-radius: 16px;
}
-.auth_clientbox .accountbox .flexbox p{
+
+.auth_clientbox .accountbox .flexbox p {
width: calc(100% - 8px);
margin: auto auto auto 8px;
font-weight: normal;
@@ -6450,12 +6678,14 @@ noscript .noscript_modal .inner .center_text p {
line-height: 16px;
color: var(--text-color);
}
-.auth_clientbox .callbackbox{
+
+.auth_clientbox .callbackbox {
width: calc(100% - 32px);
height: fit-content;
margin: 16px;
}
-.auth_clientbox .callbackbox p{
+
+.auth_clientbox .callbackbox p {
font-family: var(--Mono-fonts), sans-serif;
font-weight: normal;
font-size: 14px;
@@ -6535,6 +6765,15 @@ noscript .noscript_modal .inner .center_text p {
flex-wrap: wrap;
}
+ .userheader .icon .status {
+ position: relative;
+ left: calc(148px - (24px + 8px));
+ top: -37px;
+ width: 24px;
+ height: 24px;
+ border-radius: 50%;
+ }
+
.userheader .profile p {
margin-left: 12px;
margin-right: 12px;
@@ -8478,6 +8717,10 @@ noscript .noscript_modal .inner .center_text p {
border: 1px solid var(--main-color);
}
+ .userheader .icon .status {
+ border: solid 4px var(--dark-sub-color);
+ }
+
.fzone .follow .fbtn {
background-color: var(--main-color);
color: var(--sub-color);
@@ -8785,7 +9028,7 @@ noscript .noscript_modal .inner .center_text p {
color: var(--dark-subtext-color);
}
- .modal-content .scope_desc{
+ .modal-content .scope_desc {
color: var(--dark-text-color);
}
@@ -8845,7 +9088,7 @@ noscript .noscript_modal .inner .center_text p {
color: var(--dark-subtext-color);
}
- .report_summary .count{
+ .report_summary .count {
color: var(--subtext-color);
background-color: var(--dark-sub-color);
border: solid 1px var(--dark-border-color);
@@ -9347,21 +9590,25 @@ noscript .noscript_modal .inner .center_text p {
border: solid 1px var(--dark-border-color);
}
- .auth_clientbox{
+ .auth_clientbox {
background-color: var(--dark-background-color);
border: solid 1px var(--dark-border-color);
}
- .auth_clientbox .flexbox p{
+
+ .auth_clientbox .flexbox p {
color: var(--dark-text-color);
}
- .auth_clientbox .about .scopebox{
+
+ .auth_clientbox .about .scopebox {
border: solid 1px var(--dark-border-color);
background-color: var(--dark-sub-color);
}
- .auth_clientbox .accountbox .flexbox p{
+
+ .auth_clientbox .accountbox .flexbox p {
color: var(--dark-text-color);
}
- .auth_clientbox .callbackbox p{
+
+ .auth_clientbox .callbackbox p {
color: var(--dark-text-color);
}
}
\ No newline at end of file
diff --git a/function/function.php b/function/function.php
index 0c4994d..4468917 100644
--- a/function/function.php
+++ b/function/function.php
@@ -243,6 +243,28 @@ function uwuzuUserLogin($session, $cookie, $ip_addr, $operation_permission = "us
}
}
+ //ログイン日時を記録---------------------------------------------------------
+ $last_login_datetime = date("Y-m-d H:i:s", time());
+ $pdo->beginTransaction();
+ try {
+ $updateQuery = $pdo->prepare("UPDATE account SET last_login_datetime = :last_login_datetime WHERE userid = :userid");
+ $updateQuery->bindValue(':last_login_datetime', $last_login_datetime, PDO::PARAM_STR);
+ $updateQuery->bindValue(':userid', $userid, PDO::PARAM_STR);
+ $res = $updateQuery->execute();
+
+ if($res){
+ $pdo->commit();
+ }else{
+ // ロールバック
+ $pdo->rollBack();
+ actionLog($userid, "error", "uwuzuUserLogin", null, "最終ログイン日時を記録できませんでした!", 3);
+ }
+ } catch (Exception $e) {
+ // ロールバック
+ $pdo->rollBack();
+ actionLog($userid, "error", "uwuzuUserLogin", null, $e, 4);
+ }
+
//JobがあればJobを実行する---------------------------------------------------
$job = getJob($pdo, $userid);
if(!(empty($job))){
@@ -3746,6 +3768,12 @@ function FormatUeuseItem(array $value, string $myblocklist, string $mybookmark,
? $value['iconname']
: "../" . $value['iconname'];
+ if(isset($value["other_settings"])) {
+ $value["isAIBlock"] = val_OtherSettings("isAIBlock", $value["other_settings"]);
+ } else {
+ $value["isAIBlock"] = false;
+ }
+
$value = to_null($value);
$value = to_array_safetext($value);
$value["role"] = explode(',', $value["role"]);
@@ -3772,6 +3800,12 @@ function FormatUeuseItem(array $value, string $myblocklist, string $mybookmark,
$reusedUserData = getUserData($pdo, $reused['account']);
$reusedUserData["role"] = explode(',', $reusedUserData["role"]);
+ if(isset($reusedUserData["other_settings"])) {
+ $reusedUserData["isAIBlock"] = val_OtherSettings("isAIBlock", $reusedUserData["other_settings"]);
+ } else {
+ $reusedUserData["isAIBlock"] = false;
+ }
+
$reused = to_null($reused);
$reused = to_array_safetext($reused);
@@ -3794,6 +3828,7 @@ function FormatUeuseItem(array $value, string $myblocklist, string $mybookmark,
: "../" . $reusedUserData['iconname'],
"role" => $reusedUserData["role"],
"is_bot" => $reusedUserData["is_bot"],
+ "is_aiblock" => (bool)$reusedUserData["isAIBlock"],
],
"ueuse" => $reused["ueuse"],
"photo1" => $reused["photo1"],
@@ -3833,6 +3868,7 @@ function FormatUeuseItem(array $value, string $myblocklist, string $mybookmark,
"iconurl" => $value['iconname'],
"role" => $value["role"],
"is_bot" => $value["is_bot"],
+ "is_aiblock" => (bool)$value["isAIBlock"],
],
"ueuse" => $value["ueuse"],
"photo1" => $value["photo1"],
@@ -3862,7 +3898,7 @@ function FormatUeuseItem(array $value, string $myblocklist, string $mybookmark,
return $ueuse;
}
-function GetAPIScopes($scope){
+function GetAPIScopes($scope, $is_admin = false){
$scopelist = [
"read:me" => "重要な情報以外の自分のアカウントの情報を見る",
"write:me" => "重要な情報以外の自分のアカウントの情報を変更する",
@@ -3876,15 +3912,37 @@ function GetAPIScopes($scope){
"write:bookmark" => "ブックマークにユーズを追加・削除する",
"read:bookmark" => "ブックマークを見る"
];
- if(empty($scope)){
- return $scopelist;
- }else{
- if(array_key_exists($scope, $scopelist)){
- return $scopelist[$scope];
+
+ $admin_scopelist = [
+ 'read:admin:users' => '[Admin] 重要な情報を含めたユーザーのアカウント情報を見る',
+ 'write:admin:user-sanction' => '[Admin] ユーザーに通知・凍結/凍結解除・BANする',
+ 'read:admin:reports' => '[Admin] 通報を取得する',
+ 'write:admin:reports' => '[Admin] 通報を解決する'
+ ];
+
+ if($is_admin === false){
+ if(empty($scope)){
+ return $scopelist;
}else{
- return false;
+ if(array_key_exists($scope, $scopelist)){
+ return $scopelist[$scope];
+ }else{
+ return false;
+ }
+ }
+ }else{
+ $admin_all_scopes = array_merge($scopelist, $admin_scopelist);
+ if(empty($scope)){
+ return $admin_all_scopes;
+ }else{
+ if(array_key_exists($scope, $admin_all_scopes)){
+ return $admin_all_scopes[$scope];
+ }else{
+ return false;
+ }
}
}
+
}
function MinimumHash($text) {
@@ -4021,7 +4079,19 @@ function APIAuth($pdo, $token, $scope){
$allow_scope = array_unique(array_map('trim', explode(",", $tokenData["scope"])));
if(in_array($scope, $allow_scope)){
$userdata = getUserData($pdo, $tokenData["userid"]);
+
if(!(empty($userdata))){
+ if($userdata["admin"] == "yes"){
+ $admin_permission = true;
+ }else{
+ $admin_permission = false;
+ }
+ foreach ($allow_scope as $scope) {
+ $description = GetAPIScopes($scope, $admin_permission);
+ if ($description === false) {
+ return [false, "token_invalid_scope", null];
+ }
+ }
if($userdata["role"] === "ice"){
return [false, "this_account_has_been_frozen", null];
}else{
@@ -4059,7 +4129,7 @@ function getDatasUeuse(PDO $pdo, array $messages): array {
$users = [];
if (!empty($userIds)) {
$placeholders = implode(',', array_fill(0, count($userIds), '?'));
- $stmt = $pdo->prepare("SELECT userid, username, profile, role, iconname, headname, sacinfo FROM account WHERE userid IN ($placeholders)");
+ $stmt = $pdo->prepare("SELECT userid, username, profile, role, iconname, headname, sacinfo, other_settings FROM account WHERE userid IN ($placeholders)");
$stmt->execute($userIds);
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$users[$row['userid']] = $row;
@@ -4096,6 +4166,7 @@ function getDatasUeuse(PDO $pdo, array $messages): array {
$message['iconname'] = $userRow['iconname'] ?? ($message['iconname'] ?? null);
$message['headname'] = $userRow['headname'] ?? ($message['headname'] ?? null);
$message['sacinfo'] = $userRow['sacinfo'] ?? ($message['sacinfo'] ?? null);
+ $message['other_settings'] = $userRow['other_settings'] ?? ($message['other_settings'] ?? null);
}
// reply / reuse
diff --git a/home/index.php b/home/index.php
index 5ae4c34..19548e0 100644
--- a/home/index.php
+++ b/home/index.php
@@ -290,6 +290,7 @@ if ("serviceWorker" in navigator) {
![]()
+
@@ -638,12 +639,11 @@ $(document).ready(function() {
dataType: 'json',
success: function(response) {
if (response.success) {
+ // いいね成功時の処理
if (isLiked) {
$this.removeClass('bookmark_after'); // クラスを削除していいねを取り消す
- view_notify("ブックマークを解除しました");
} else {
$this.addClass('bookmark_after'); // クラスを追加していいねを追加する
- view_notify("ユーズをブックマークしました!");
}
} else {
// いいね失敗時の処理
@@ -687,7 +687,6 @@ $(document).ready(function() {
success: function (response) {
if (response.success) {
postElement.remove();
- view_notify("ユーズを削除しました!");
} else {
view_notify("ユーズの削除に失敗しました");
}
diff --git a/js/nsfw_event.js b/js/nsfw_event.js
index 022f438..ba9f758 100644
--- a/js/nsfw_event.js
+++ b/js/nsfw_event.js
@@ -12,6 +12,7 @@ $(document).on('click', '.mini_irobtn', function (event) {
$(document).on('click', '#ueuse_image', function (event) {
var imgLink = $(this).attr('src');
+ var imgAIBlock = $(this).attr('data-aiblock');
var modal = $('#Big_ImageModal');
var modalMain = $('.modal-content');
@@ -19,6 +20,12 @@ $(document).on('click', '#ueuse_image', function (event) {
$(modalimg_zone).attr('src',imgLink);
+ if(imgAIBlock == "true"){
+ $("#NoAI_Footer").show();
+ }else{
+ $("#NoAI_Footer").hide();
+ }
+
modal.show();
modalMain.addClass("slideUp");
modalMain.removeClass("slideDown");
diff --git a/js/view_function.js b/js/view_function.js
index 8936994..fed23da 100644
--- a/js/view_function.js
+++ b/js/view_function.js
@@ -312,6 +312,8 @@ function formatMarkdown(text) {
return key;
}
+ text = text.replaceAll(''', "'");
+
// 複数行コードブロック (```)
text = text.replace(/```([\s\S]+?)```/g, (match, code) => {
// 先頭の改行のみ削除
@@ -518,10 +520,19 @@ function getBotIcon(userdata) {
return "";
}
+function getAIBlockFlag(userdata) {
+ if (userdata["is_aiblock"] && userdata["is_aiblock"] == true) {
+ return `data-aiblock = "true"`;
+ }else{
+ return `data-aiblock = "false"`;
+ }
+}
+
async function createUeuseHtml(ueuse, selectedUniqid = null) {
let html = "";
let check = "";
let bot = "";
+ let AIBlock = "";
var reuse = "";
let contentHtml = "";
@@ -557,6 +568,7 @@ async function createUeuseHtml(ueuse, selectedUniqid = null) {
if (ueuse["reuse"]) {
check = getCheckIcon(ueuse["userdata"]);
bot = getBotIcon(ueuse["userdata"]);
+ AIBlock = getAIBlockFlag(ueuse["userdata"]);
}
if (ueuse["ueuse"].length > 0) {
@@ -621,6 +633,9 @@ async function createUeuseHtml(ueuse, selectedUniqid = null) {
abi_date = ueuse["abi"]["abi_date"];
} else {
if (!(ueuse["reuse"] == null)) {
+ check = getCheckIcon(ueuse["reuse"]["userdata"]);
+ bot = getBotIcon(ueuse["reuse"]["userdata"]);
+ AIBlock = getAIBlockFlag(ueuse["reuse"]["userdata"]);
reuse = `
@@ -693,6 +708,7 @@ async function createUeuseHtml(ueuse, selectedUniqid = null) {
} else if (ueuse["type"] == "Reply") {
check = getCheckIcon(ueuse["userdata"]);
bot = getBotIcon(ueuse["userdata"]);
+ AIBlock = getAIBlockFlag(ueuse["userdata"]);
if (selectedUniqid != null && selectedUniqid == ueuse["uniqid"]) {
reuse = ``;
@@ -757,6 +773,7 @@ async function createUeuseHtml(ueuse, selectedUniqid = null) {
} else {
check = getCheckIcon(ueuse["userdata"]);
bot = getBotIcon(ueuse["userdata"]);
+ AIBlock = getAIBlockFlag(ueuse["userdata"]);
reuse = ``;
inyo = ``;
@@ -858,29 +875,29 @@ async function createUeuseHtml(ueuse, selectedUniqid = null) {
if (img4.length > 0) {
img_html = ``;
} else {
img_html = ``;
@@ -888,17 +905,17 @@ async function createUeuseHtml(ueuse, selectedUniqid = null) {
} else {
img_html = ``;
}
} else {
img_html = ``;
}
diff --git a/others/index.php b/others/index.php
index 40ff345..d15ee52 100644
--- a/others/index.php
+++ b/others/index.php
@@ -68,6 +68,11 @@ $notificationcount = $notiData['notification_count'];
if (!empty($pdo)) {
$userData = getUserData($pdo, $userid);
+ if($is_Admin == "yes"){
+ $admin_permission = true;
+ }else{
+ $admin_permission = false;
+ }
$apitokenQuery = $pdo->prepare("SELECT * FROM api WHERE userid = :userid ORDER BY datetime DESC");
$apitokenQuery->bindValue(':userid', $userid);
@@ -309,8 +314,8 @@ require('../logout/logout.php');
$client_scope_base = array_unique(array_map('trim', explode(",", $value["scope"])));
$client_scope = [];
foreach ($client_scope_base as $scope) {
- if (GetAPIScopes($scope)) {
- $client_scope[] = GetAPIScopes($scope);
+ if (GetAPIScopes($scope, $admin_permission)) {
+ $client_scope[] = GetAPIScopes($scope, $admin_permission);
} else {
$client_scope[] = "未知のスコープ ($scope)";
}
@@ -372,7 +377,7 @@ require('../logout/logout.php');
許可する権限
$label) { ?>
diff --git a/search/index.php b/search/index.php
index 8cfbc79..ad0d2b3 100644
--- a/search/index.php
+++ b/search/index.php
@@ -204,6 +204,7 @@ $pdo = null;
![]()
+
@@ -367,8 +368,10 @@ $(document).ready(function() {
// いいね成功時の処理
if (isLiked) {
$this.removeClass('bookmark_after'); // クラスを削除していいねを取り消す
+ view_notify("ブックマークを解除しました");
} else {
$this.addClass('bookmark_after'); // クラスを追加していいねを追加する
+ view_notify("ユーズをブックマークしました!");
}
} else {
// いいね失敗時の処理
diff --git a/server/uwuzuinfo.txt b/server/uwuzuinfo.txt
index 3bcfbad..418ed57 100644
--- a/server/uwuzuinfo.txt
+++ b/server/uwuzuinfo.txt
@@ -1,4 +1,4 @@
uwuzu
-1.6.7
-2025/12/26
+1.6.8
+2025/12/30
daichimarukana,putonfps
\ No newline at end of file
diff --git a/server/uwuzurelease.txt b/server/uwuzurelease.txt
index 24bdc3f..9fe52b5 100644
--- a/server/uwuzurelease.txt
+++ b/server/uwuzurelease.txt
@@ -1,6 +1,37 @@
## リリースノートだぜぇぇぇぇぇぇい!!!!!!!
ここにはuwuzuの更新情報を載せてくぜぇ~!(いやまてテンションおかしいだろ...)
+## Version 1.6.8 (Hapuego)
+2025/12/26
+fix: 不要なコードを削除しました!
+fix: 一部UIの崩れを修正しました!
+fix: アポストロフィーが正しく表示されない問題を修正しました!
+fix: 管理者からユーザーに通知を送信する際に、通知のタイトルが128文字までしか入力できない問題を修正しました!
+fix: サーバーの環境次第で、管理者ページより概要ページで発生するおそれのあるゼロ除算エラーを修正しました!
+fix: 公式マークを持つユーザーもしくはBotユーザーのユーズをリユーズすると、チェックマークおよびBotラベルが表示されなくなる問題を修正しました!
+fix: 一部ページでブックマーク追加時に画面上からお知らせが出ない問題を修正しました!
+chg: APIスコープに関する整合性とセキュリティを向上させました!
+chg: 一部UIを変更しました!
+new: 管理者向け機能でアクティブユーザー数の統計情報とユーザーのオンラインステータスを確認できる機能を追加しました!
+ この機能を使用するにはデータベースの更新が必要となります。
+ データベースのaccountテーブルにlast_login_datetime(datetime)というカラムを追加してください。
+new: オンラインステータス公開機能を追加しました!
+ メニューより、「設定」→「プロフィール」内のオンラインステータスを公開するをオンにするとオンラインステータスがユーザーのプロフィールページに公開されます。
+ ステータスは以下の種類があります。
+ - 🟢: オンライン - 過去5分間以内にuwuzuを利用した
+ - 🟡: 離席中 - 過去15分から過去5分までの間にuwuzuを利用した
+ - ⚪: オフライン - 最後にuwuzuを利用してから15分間以上経過している
+ - 表示なし: オンラインステータスの表示をオンにしていない
+new: 管理者向けAPIを追加しました!
+ これにより以下の操作がAPI経由で行えるようになります。
+ APIの使用方法はdocs.uwuzu.comをご確認ください!
+ - 重要な情報を含めたユーザーのアカウント情報を見る
+ - ユーザーに通知・凍結/凍結解除・BANする
+ - 通報を取得する
+ - 通報を解決する
+new: AIによる学習を拒否する機能を強化しました!
+ これにより、AIによる学習を拒否する設定がオンの場合に、uwuzu上で画像を表示すると画像の下に「No AI 機械学習への利用を一切拒否します。」と表示されるようになります。
+
## Version 1.6.7 (Hapuego)
2025/12/26
fix: 通知ページにてユーザー名に含まれるカスタム絵文字が横にぎゅっと表示されてしまう問題を修正しました!
diff --git a/settings/index.php b/settings/index.php
index fa009cf..217db91 100644
--- a/settings/index.php
+++ b/settings/index.php
@@ -88,6 +88,7 @@ if( !empty($pdo) ) {
$isAIBlock = val_OtherSettings("isAIBlock", $userData["other_settings"]);
$isAIBWM = val_OtherSettings("isAIBlockWaterMark", $userData["other_settings"]);
+ $isPublicOnlineStatus = val_OtherSettings("isPublicOnlineStatus", $userData["other_settings"]);
if(!(empty($userData["encryption_ivkey"]))){
$view_mailadds = DecryptionUseEncrKey($userData["mailadds"], GenUserEnckey($userData["datetime"]), $userData["encryption_ivkey"]);
@@ -146,31 +147,17 @@ if( !empty($_POST['btn_submit']) ) {
$mailadds = safetext($_POST['mailadds']);
- if( !empty($_POST['isAIBlock']) ) {
- $new_isAIBlock = safetext($_POST['isAIBlock']);
- }else{
- $new_isAIBlock = "false";
+ $targets = [
+ 'isAIBlock' => 'isAIBlock',
+ 'isAIBMW' => 'isAIBlockWaterMark',
+ 'isPublicOnlineStatus' => 'isPublicOnlineStatus'
+ ];
+ $other_settings_json = $userData["other_settings"];
+ foreach ($targets as $post_key => $save_key) {
+ $is_true = (!empty($_POST[$post_key]) && safetext($_POST[$post_key]) === "true");
+ $other_settings_json = val_AddOtherSettings($save_key, $is_true, $other_settings_json);
}
- if($new_isAIBlock === "true"){
- $save_isAIBlock = true;
- }else{
- $save_isAIBlock = false;
- }
- $other_settings_json = val_AddOtherSettings("isAIBlock", $save_isAIBlock, $userData["other_settings"]);
-
- if( !empty($_POST['isAIBMW']) ) {
- $new_isAIBMW = safetext($_POST['isAIBMW']);
- }else{
- $new_isAIBMW = "false";
- }
- if($new_isAIBMW === "true"){
- $save_isAIBMW = true;
- }else{
- $save_isAIBMW = false;
- }
- $other_settings_json = val_AddOtherSettings("isAIBlockWaterMark", $save_isAIBMW, $other_settings_json);
-
if( !empty($_POST['mail_important']) ) {
$mail_important = safetext($_POST['mail_important']);
}else{
@@ -612,6 +599,19 @@ $pdo = null;
+
+
オンラインステータスを公開する
+
プロフィール画面にあなたのオンラインステータスを表示するかを選択できます。
+ この設定はAPIにも反映されます。
+
+
+
+
+
+
+
+
+
diff --git a/settings_admin/overview_admin.php b/settings_admin/overview_admin.php
index 6fa35c1..1ca607b 100644
--- a/settings_admin/overview_admin.php
+++ b/settings_admin/overview_admin.php
@@ -84,21 +84,29 @@ $notiData = $notiQuery->fetch(PDO::FETCH_ASSOC);
$notificationcount = $notiData['notification_count'];
if(!empty($pdo)){
- mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
- $mysqli = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
-
- //User
- $result = $mysqli->query("SELECT userid FROM account");
- $count1 = $result->num_rows;
- //ueuse
- $result2 = $mysqli->query("SELECT uniqid FROM ueuse");
- $count2 = $result2->num_rows;
- //emoji
- $result3 = $mysqli->query("SELECT sysid FROM emoji");
- $count3 = $result3->num_rows;
- //bot
- $result4 = $mysqli->query("SELECT userid FROM account WHERE sacinfo = 'bot'");
- $count4 = $result4->num_rows;
+ try {
+ //User
+ $count1 = $pdo->query("SELECT userid FROM account")->rowCount();
+ //Ueuse
+ $count2 = $pdo->query("SELECT uniqid FROM ueuse")->rowCount();
+ //Emoji
+ $count3 = $pdo->query("SELECT sysid FROM emoji")->rowCount();
+ // bot
+ $count4 = $pdo->query("SELECT userid FROM account WHERE sacinfo = 'bot'")->rowCount();
+ // ActiveUsers
+ $count5 = $pdo->query("SELECT userid FROM account WHERE last_login_datetime > NOW() - INTERVAL 5 MINUTE")->rowCount();
+ // AwayUsers
+ $count6 = $pdo->query("SELECT userid FROM account WHERE last_login_datetime < NOW() - INTERVAL 5 MINUTE AND last_login_datetime >= NOW() - INTERVAL 15 MINUTE")->rowCount();
+ } catch (PDOException $e) {
+ $count1 = 0;
+ $count2 = 0;
+ $count3 = 0;
+ $count4 = 0;
+ $count5 = 0;
+ $count6 = 0;
+ $error_message[] = $e->getMessage();
+ actionLog($userid, "error", "overview_admin", null, "統計情報の取得に失敗しました!", 4);
+ }
$migrationUserFollow = checkFollowMigrationProgress($pdo);
@@ -162,45 +170,50 @@ if(!empty($pdo)){
if(function_exists("disk_free_space")){
- if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
- $disk = true;
- $diskFree = (int) disk_free_space('C:') / 1024 / 1024;
- $diskTotal = (int) disk_total_space('C:') / 1024 / 1024;
- $diskUmari = $diskTotal - $diskFree;
- if ($diskFree / $diskTotal < 0.1) {
- $disk_over90p = true;
- }else{
- $disk_over90p = false;
- }
-
- $loadAve = null;
- } else {
- $disk = true;
- $diskFree = (int) disk_free_space('/') / 1024 / 1024;
- $diskTotal = (int) disk_total_space('/') / 1024 / 1024;
- $diskUmari = $diskTotal - $diskFree;
- if ($diskFree / $diskTotal < 0.1) {
- $disk_over90p = true;
- }else{
- $disk_over90p = false;
- }
- if(function_exists("sys_getloadavg")){
- $loadAve = sys_getloadavg()[0];
- }else{
- $loadAve = null;
- }
- }
-}else{
- $disk = false;
- $diskFree = 5000;
- $diskUmari = 5000;
- $diskTotal = 10000;
- $disk_over90p = false;
- if(function_exists("sys_getloadavg")){
- $loadAve = sys_getloadavg()[0];
- }else{
- $loadAve = null;
- }
+ if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
+ $disk = true;
+ $totalRaw = disk_total_space('C:');
+ $diskTotal = ($totalRaw > 0) ? (int)$totalRaw / 1024 / 1024 : 0;
+ $diskFree = (int)disk_free_space('C:') / 1024 / 1024;
+ $diskUmari = $diskTotal - $diskFree;
+
+ if ($diskTotal > 0 && ($diskFree / $diskTotal < 0.1)) {
+ $disk_over90p = true;
+ } else {
+ $disk_over90p = false;
+ }
+
+ $loadAve = null;
+ } else {
+ $disk = true;
+ $totalRaw = disk_total_space('/');
+ $diskTotal = ($totalRaw > 0) ? (int)$totalRaw / 1024 / 1024 : 0;
+ $diskFree = (int)disk_free_space('/') / 1024 / 1024;
+ $diskUmari = $diskTotal - $diskFree;
+
+ if ($diskTotal > 0 && ($diskFree / $diskTotal < 0.1)) {
+ $disk_over90p = true;
+ } else {
+ $disk_over90p = false;
+ }
+
+ if(function_exists("sys_getloadavg")){
+ $loadAve = sys_getloadavg()[0];
+ } else {
+ $loadAve = null;
+ }
+ }
+} else {
+ $disk = false;
+ $diskFree = 5000;
+ $diskUmari = 5000;
+ $diskTotal = 10000;
+ $disk_over90p = false;
+ if(function_exists("sys_getloadavg")){
+ $loadAve = sys_getloadavg()[0];
+ }else{
+ $loadAve = null;
+ }
}
@@ -289,6 +302,16 @@ require('../logout/logout.php');
+
+
+
+
離席中のユーザー数
(過去5分~15分間)
+
+
+
ディスク空き容量
@@ -297,10 +320,17 @@ require('../logout/logout.php');
ディスク空き容量には余裕があります。
+
-
+ 0) ? round($usedGB / $totalGB * 100, 1) : 0;
+ ?>
+
+
使用済み : GB
空き容量 : GB
diff --git a/settings_admin/userinfo.php b/settings_admin/userinfo.php
index e8b6b15..c039919 100644
--- a/settings_admin/userinfo.php
+++ b/settings_admin/userinfo.php
@@ -95,6 +95,31 @@ if (!empty($pdo)) {
$view_ip_addr = $userdata["last_ip"];
}
+ if (!(empty($userdata["last_login_datetime"]))) {
+ $lastLogin = new DateTime($userdata["last_login_datetime"]);
+ $now = new DateTime();
+
+ $interval = $now->diff($lastLogin);
+
+ $minutesPast = ($interval->days * 24 * 60) + ($interval->h * 60) + $interval->i;
+
+ $status_datetime = $userdata["last_login_datetime"];
+
+ if ($minutesPast <= 5) {
+ $status_color = "green";
+ $status = "Online";
+ } elseif ($minutesPast <= 15) {
+ $status_color = "yellow";
+ $status = "Away";
+ } else {
+ $status_color = "gray";
+ $status = "Offline";
+ }
+ } else {
+ $status_color = "gray";
+ $status = "Offline";
+ }
+
$roles = array_filter(explode(',', $userdata["role"]));
$roleDataArray = array();
@@ -123,7 +148,7 @@ if( !empty($_POST['send_notification_submit']) ) {
$notice_msg = safetext($_POST['notice_msg']);
if(empty($notice_title)){
$error_message[] = "通知のタイトルを空欄にすることはできません。(INPUT_PLEASE)";
- }elseif(mb_strlen($notice_title) > 128){
+ }elseif(mb_strlen($notice_title) > 512){
$error_message[] = "通知のタイトルを512文字以上にすることはできません。(INPUT_OVER_MAX_COUNT)";
}
if(empty($notice_msg)){
@@ -283,7 +308,7 @@ if( !empty($_POST['send_water_submit']) ) {
if( !empty($view_mailadds) ){
if(filter_var($view_mailadds, FILTER_VALIDATE_EMAIL)){
$mail_title = "お使いの".safetext($serversettings["serverinfo"]["server_name"])."アカウントは解凍されました!";
- $mail_text = "".$userdata["username"]."(".$userdata["userid"].")さん いつもuwuzuをご利用いただきありがとうございます。 ご利用のアカウント(".$userdata["userid"].")が解凍されたためお知らせいたします。 今後、ご利用のuwuzuアカウントは今まで通りご利用いただけます。 また、APIを使用している方はAPIのトークンがリセットされているため再度トークンを発行してご利用ください。";
+ $mail_text = "".$userdata["username"]."(".$userdata["userid"].")さん いつもuwuzuをご利用いただきありがとうございます。 ご利用のアカウント(".$userdata["userid"].")が解凍されたためお知らせいたします。 今後、ご利用のuwuzuアカウントは今まで通りご利用いただけます。";
$error_message[] = send_html_mail($view_mailadds,$mail_title,$mail_text,"../");
}
@@ -298,7 +323,7 @@ if( !empty($_POST['send_water_submit']) ) {
try {
$touserid = safetext($userdata['userid']);
$datetime = safetext(date("Y-m-d H:i:s"));
- $msg = safetext("サービス管理者によりお使いのアカウントは解凍されました!\n今まで通りご利用いただけます。\nなお、APIを使用している方はAPIのトークンがリセットされているため再度トークンを発行してご利用ください。");
+ $msg = safetext("サービス管理者によりお使いのアカウントは解凍されました!\n今まで通りご利用いただけます。");
$title = safetext("🫗お使いのアカウントが解凍されました!🫗");
$url = safetext("/home");
$userchk = 'none';
@@ -420,6 +445,11 @@ require('../logout/logout.php');
diff --git a/ueuse/index.php b/ueuse/index.php
index 118bbd9..824a489 100644
--- a/ueuse/index.php
+++ b/ueuse/index.php
@@ -294,6 +294,7 @@ $pdo = null;
![]()
+
diff --git a/update.json b/update.json
index 5a378de..0c63194 100644
--- a/update.json
+++ b/update.json
@@ -1,33 +1,31 @@
{
"software": "uwuzu",
- "version": "1.6.7",
- "release_date": "2025/12/26",
- "release_notes": "このアップデートには、パスワードの復元に関する脆弱性の修正が含まれます。\nまた、パレットイメージが投稿できない問題など、いくつかのバグ修正が含まれます!\n詳細はリリースノートをご確認ください。",
- "notices": "アップデート前にデータのバックアップを行うことをおすすめします!",
+ "version": "1.6.8",
+ "release_date": "2025/12/30",
+ "release_notes": "このアップデートには、アポストロフィーが正しく表示されない問題の修正や、一部ページでブックマーク追加時に画面上からお知らせが出ない問題の修正など、いくつかのバグ修正が含まれます!\nまた、新機能でオンラインステータス機能と管理者向けAPIが含まれます!\n詳細はリリースノートをご確認ください。",
+ "notices": "アップデートの前にデータベース構造の更新が必要です。リリースノートの案内に沿って更新をしてからアップデートをしてください。\nアップデート前にデータのバックアップを行うことをおすすめします!",
"files": {
"overwrite": [
- "/admin/addadmin.php",
- "/admin/index.php",
- "/admin/setup_db_php.php",
- "/admin/setup_uwuzu_db.php",
- "/admin/success.php",
- "/css/home.css",
- "/js/view_function.js",
- "/settings_admin/api/update_query.php",
"/uwuzu_error_code.txt",
- "/function/function.php",
- "/nextpage/notification.php",
- "/bookmark/bookmark.php",
+ "/api/auth.php",
+ "/api/admin/reports/index.php",
+ "/api/admin/reports/resolve.php",
+ "/api/admin/users/index.php",
+ "/api/admin/users/sanction.php",
+ "/api/users/index.php",
"/bookmark/index.php",
+ "/css/home.css",
+ "/function/function.php",
"/home/index.php",
+ "/js/nsfw_event.js",
+ "/js/view_function.js",
+ "/others/index.php",
+ "/search/index.php",
"/settings/index.php",
+ "/settings_admin/overview_admin.php",
+ "/settings_admin/userinfo.php",
"/ueuse/index.php",
"/user/index.php",
- "/img/sysimage/errorimage/icon_404.png",
- "/passrecovery/badrecovery.php",
- "/passrecovery/donerecovery.php",
- "/passrecovery/index.php",
- "/passrecovery/startrecovery.php",
"/server/uwuzuabout.txt",
"/server/uwuzuinfo.txt",
"/server/uwuzurelease.txt"
diff --git a/user/index.php b/user/index.php
index 93a2d7a..262728f 100644
--- a/user/index.php
+++ b/user/index.php
@@ -110,7 +110,7 @@ if (!empty($pdo)) {
if($is_local == true){
$roles = array_filter(explode(',', $userData["role"])); // カンマで区切られたロールを配列に分割
- $rerole = $pdo->prepare("SELECT follow, follower,blocklist, username, userid, password, mailadds, profile, iconname, headname, role, datetime, other_settings FROM account WHERE userid = :userid");
+ $rerole = $pdo->prepare("SELECT follow, follower,blocklist, username, userid, password, mailadds, profile, iconname, headname, role, datetime, other_settings, last_login_datetime FROM account WHERE userid = :userid");
$rerole->bindValue(':userid', $userData["userid"]);
// SQL実行
@@ -129,6 +129,37 @@ if (!empty($pdo)) {
$isAIBlock = val_OtherSettings("isAIBlock", $userdata["other_settings"]);
+ $isPublicOnlineStatus = val_OtherSettings("isPublicOnlineStatus", $userdata["other_settings"]);
+ if($isPublicOnlineStatus === true){
+ if (!(empty($userdata["last_login_datetime"]))) {
+ $lastLogin = new DateTime($userdata["last_login_datetime"]);
+ $now = new DateTime();
+
+ $interval = $now->diff($lastLogin);
+
+ $minutesPast = ($interval->days * 24 * 60) + ($interval->h * 60) + $interval->i;
+
+ $status_datetime = $userdata["last_login_datetime"];
+
+ if ($minutesPast <= 5) {
+ $status_color = "green";
+ $status = "オンライン";
+ } elseif ($minutesPast <= 15) {
+ $status_color = "yellow";
+ $status = "離席中";
+ } else {
+ $status_color = "gray";
+ $status = "オフライン";
+ }
+ } else {
+ $status_color = "gray";
+ $status = "オフライン";
+ }
+ }else{
+ $status = null;
+ }
+
+
//-------フォロー数---------
$follow = getFolloweeList($pdo, $userData["userid"]); // コンマで区切られたユーザーIDを含む変数
$followCount = count($follow);
@@ -203,6 +234,8 @@ if (!empty($pdo)) {
$ueuse_cnt = "zero";
$followCount = "zero";
$followerCount = "zero";
+
+ $status = null;
}
} else {
@@ -213,59 +246,60 @@ if (!empty($pdo)) {
$ueuse_cnt = "zero";
$followCount = "zero";
$followerCount = "zero";
+
+ $status = null;
}
}
-if (!empty($_POST['follow'])) {
- $res_follow = follow_user($pdo, $userData['userid'], $userid);
- if($res_follow === false){
- $error_message[] = '更新に失敗しました。(REGISTERED_DAME)';
- }else{
- $url = (empty($_SERVER['HTTPS']) ? 'http://' : 'https://') . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
- header("Location:" . $url);
- exit;
+if($is_local == true){
+ if (!empty($_POST['follow'])) {
+ $res_follow = follow_user($pdo, $userData['userid'], $userid);
+ if($res_follow === false){
+ $error_message[] = '更新に失敗しました。(REGISTERED_DAME)';
+ }else{
+ $url = (empty($_SERVER['HTTPS']) ? 'http://' : 'https://') . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
+ header("Location:" . $url);
+ exit;
+ }
+ } elseif (!empty($_POST['unfollow'])) {
+ $res_unfollow = unfollow_user($pdo, $userData['userid'], $userid);
+ if($res_unfollow === false){
+ $error_message[] = '更新に失敗しました。(REGISTERED_DAME)';
+ }else{
+ $url = (empty($_SERVER['HTTPS']) ? 'http://' : 'https://') . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
+ header("Location:" . $url);
+ exit;
+ }
}
-} elseif (!empty($_POST['unfollow'])) {
- $res_unfollow = unfollow_user($pdo, $userData['userid'], $userid);
- if($res_unfollow === false){
- $error_message[] = '更新に失敗しました。(REGISTERED_DAME)';
- }else{
- $url = (empty($_SERVER['HTTPS']) ? 'http://' : 'https://') . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
- header("Location:" . $url);
- exit;
+
+ if (!empty($_POST['send_block_submit'])) {
+ $res_block = block_user($pdo, $userData['userid'], $userid);
+ if($res_block === false){
+ $error_message[] = '更新に失敗しました。(REGISTERED_DAME)';
+ }else{
+ $url = (empty($_SERVER['HTTPS']) ? 'http://' : 'https://') . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
+ header("Location:" . $url);
+ exit;
+ }
+ } elseif (!empty($_POST['send_un_block_submit'])) {
+ $res_unblock = unblock_user($pdo, $userData['userid'], $userid);
+ if($res_unblock === false){
+ $error_message[] = '更新に失敗しました。(REGISTERED_DAME)';
+ }else{
+ $url = (empty($_SERVER['HTTPS']) ? 'http://' : 'https://') . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
+ header("Location:" . $url);
+ exit;
+ }
}
}
-if (!empty($_POST['send_block_submit'])) {
- $res_block = block_user($pdo, $userData['userid'], $userid);
- if($res_block === false){
- $error_message[] = '更新に失敗しました。(REGISTERED_DAME)';
- }else{
- $url = (empty($_SERVER['HTTPS']) ? 'http://' : 'https://') . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
- header("Location:" . $url);
- exit;
- }
-} elseif (!empty($_POST['send_un_block_submit'])) {
- $res_unblock = unblock_user($pdo, $userData['userid'], $userid);
- if($res_unblock === false){
- $error_message[] = '更新に失敗しました。(REGISTERED_DAME)';
- }else{
- $url = (empty($_SERVER['HTTPS']) ? 'http://' : 'https://') . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
- header("Location:" . $url);
- exit;
- }
-}
-
-
-
require('../logout/logout.php');
?>
-
@@ -351,6 +385,9 @@ require('../logout/logout.php');
; ?>)
+
+
+
@@".safetext($activity_domain)."";} ?>
@@ -647,6 +684,7 @@ require('../logout/logout.php');
![]()
+
diff --git a/uwuzu_database.sql b/uwuzu_database.sql
index 21c00a5..94759a7 100644
--- a/uwuzu_database.sql
+++ b/uwuzu_database.sql
@@ -3,7 +3,7 @@
-- https://www.phpmyadmin.net/
--
-- ホスト: 127.0.0.1
--- 生成日時: 2025-10-27 15:05:57
+-- 生成日時: 2025-12-29 19:07:06
-- サーバのバージョン: 10.4.32-MariaDB
-- PHP のバージョン: 8.2.12
@@ -52,7 +52,8 @@ CREATE TABLE `account` (
`mail_settings` mediumtext NOT NULL,
`encryption_ivkey` varchar(256) NOT NULL,
`other_settings` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL CHECK (json_valid(`other_settings`)),
- `last_ip` varchar(1024) NOT NULL
+ `last_ip` varchar(1024) NOT NULL,
+ `last_login_datetime` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- --------------------------------------------------------
diff --git a/uwuzu_error_code.txt b/uwuzu_error_code.txt
index 00dbb66..78a31e8 100644
--- a/uwuzu_error_code.txt
+++ b/uwuzu_error_code.txt
@@ -16,6 +16,7 @@ contains_prohibited_url - 投稿禁止URLが含まれている場合に表示さ
this_account_has_been_frozen - Botのアカウントが凍結されている場合に表示されます。
token_input_error - APIのアクセストークンが不正または使用できない際に表示されます。
token_invalid - APIのアクセストークンが無効な時に表示されます。
+token_invalid_scope - 利用できないスコープが含まれている場合に表示されます。
db_error_[xxx] - BDでエラーが発生した際に表示されます。
over_rate_limit - 1分間あたりのレート制限を超過したさいに表示されます。
post_not_found - ユーズが存在しない時に表示されます。
@@ -28,6 +29,8 @@ migration_bad_success - アカウントの移行後に移行の完了処理が
already_been_completed - 処理が既に完了している場合に表示されます。
you_cant_it_to_yourself - 自分に対して行えない処理を行おうとした際に表示されます。
could_not_complete - 処理を完了できなかった場合に表示されます。
+user_not_frozen_cant_be_banned - APIからユーザーをBANしようとした際に、ユーザーが事前に凍結されていない場合に発生するエラーです。
+method_not_allowed - 禁止されたHTTPメゾットで要求があった場合に表示されます。
this_API_is_ws_only - WebsocketAPIがWebsocket以外の方法でアクセスされた場合に表示されます。
----------(UWUZU ERR CODE)----------