diff --git a/app/Http/Resources/InviteResource.php b/app/Http/Resources/InviteResource.php index 840a1eb7..7fa4ebf6 100644 --- a/app/Http/Resources/InviteResource.php +++ b/app/Http/Resources/InviteResource.php @@ -17,7 +17,7 @@ class InviteResource extends JsonResource return [ 'id' => $this->id, 'inviter' => $this->inviter, - 'invitee' => $this->inviter, + 'invitee' => $this->invitee, 'hash' => $this->hash, 'time_invited' => $this->time_invited, 'valid' => $this->valid, diff --git a/app/Http/Resources/UserResource.php b/app/Http/Resources/UserResource.php index 9f7a8bd6..54b13cac 100644 --- a/app/Http/Resources/UserResource.php +++ b/app/Http/Resources/UserResource.php @@ -32,7 +32,7 @@ class UserResource extends JsonResource 'seedtime_text' => mkprettytime($this->seedtime), 'leechtime' => $this->leechtime, 'leechtime_text' => mkprettytime($this->leechtime), - 'invitee_code' => new InviteResource($this->whenLoaded('invitee_code')), + 'inviter' => new UserResource($this->whenLoaded('inviter')), ]; } } diff --git a/app/Models/User.php b/app/Models/User.php index 280dd335..d8a2627e 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -103,7 +103,8 @@ class User extends Authenticatable public static $commonFields = [ 'id', 'username', 'email', 'class', 'status', 'added', 'avatar', - 'uploaded', 'downloaded', 'seedbonus', 'seedtime', 'leechtime' + 'uploaded', 'downloaded', 'seedbonus', 'seedtime', 'leechtime', + 'invited_by', ]; public function checkIsNormal(array $fields = ['status', 'enabled']) @@ -139,4 +140,9 @@ class User extends Authenticatable return $this->hasOne(Invite::class, 'invitee_register_uid'); } + public function inviter() + { + return $this->belongsTo(User::class, 'invited_by'); + } + } diff --git a/app/Models/UserBanLog.php b/app/Models/UserBanLog.php new file mode 100644 index 00000000..abf3b45f --- /dev/null +++ b/app/Models/UserBanLog.php @@ -0,0 +1,9 @@ +toDateTimeString(); $examUserTable = (new ExamUser())->getTable(); $examTable = (new Exam())->getTable(); + $userTable = (new User())->getTable(); $baseQuery = ExamUser::query() ->join($examTable, "$examUserTable.exam_id", "=", "$examTable.id") ->where("$examUserTable.status", ExamUser::STATUS_NORMAL) @@ -519,6 +521,7 @@ class ExamRepository extends BaseRepository $size = 100; $minId = 0; $result = 0; + while (true) { $logPrefix = sprintf('[%s], size: %s', __FUNCTION__, $size); $examUsers = (clone $baseQuery)->where("$examUserTable.id", ">", $minId)->limit($size)->get(); @@ -530,11 +533,12 @@ class ExamRepository extends BaseRepository } $result += $examUsers->count(); $now = Carbon::now()->toDateTimeString(); - $examUserIdArr = $uidToDisable = $messageToSend = []; + $examUserIdArr = $uidToDisable = $messageToSend = $userBanLog = $userModcommentUpdate = []; foreach ($examUsers as $examUser) { $minId = $examUser->id; $examUserIdArr[] = $examUser->id; $uid = $examUser->uid; + $exam = $examUser->exam; $currentLogPrefix = sprintf("$logPrefix, user: %s, exam: %s, examUser: %s", $uid, $examUser->exam_id, $examUser->id); $locale = $examUser->user->locale; if ($examUser->is_done) { @@ -547,10 +551,26 @@ class ExamRepository extends BaseRepository $msgTransKey = 'exam.checkout_not_pass_message_content'; //ban user $uidToDisable[] = $uid; + $userModcomment = nexus_trans('exam.ban_user_modcomment', [ + 'exam_name' => $exam->name, + 'begin' => $examUser->begin, + 'end' => $examUser->end + ], $locale); + $userModcommentUpdate[] = sprintf("when `id` = %s then concat_ws('\n', modcomment, '%s')", $uid, $userModcomment); + $banLogReason = nexus_trans('exam.ban_log_reason', [ + 'exam_name' => $exam->name, + 'begin' => $exam->begin, + 'end' => $exam->end, + ], $locale); + $userBanLog[] = [ + 'uid' => $uid, + 'username' => $examUser->user->username, + 'reason' => $banLogReason, + ]; } $subject = nexus_trans($subjectTransKey, [], $locale); $msg = nexus_trans($msgTransKey, [ - 'exam_name' => $examUser->exam->name, + 'exam_name' => $exam->name, 'begin' => $examUser->begin, 'end' => $examUser->end ], $locale); @@ -561,11 +581,20 @@ class ExamRepository extends BaseRepository 'msg' => $msg ]; } - DB::transaction(function () use ($uidToDisable, $messageToSend, $examUserIdArr) { + DB::transaction(function () use ($uidToDisable, $messageToSend, $examUserIdArr, $userBanLog, $userModcommentUpdate, $userTable, $logPrefix) { ExamUser::query()->whereIn('id', $examUserIdArr)->update(['status' => ExamUser::STATUS_FINISHED]); Message::query()->insert($messageToSend); if (!empty($uidToDisable)) { - User::query()->whereIn('id', $uidToDisable)->update(['enabled' => User::ENABLED_NO]); + $uidStr = implode(', ', $uidToDisable); + $sql = sprintf( + 'update %s set enabled = %s, set modcomment = case when %s end where id in (%s)', + $userTable, User::ENABLED_NO, implode(' ', $userModcommentUpdate), $uidStr + ); + $updateResult = DB::update($sql); + do_log(sprintf("$logPrefix, disable %s users: %s, sql: %s, updateResult: %s", count($uidToDisable), $uidStr, $sql, $updateResult)); + } + if (!empty($userBanLog)) { + UserBanLog::query()->insert($userBanLog); } }); } diff --git a/app/Repositories/UserRepository.php b/app/Repositories/UserRepository.php index befe9490..5d1fafef 100644 --- a/app/Repositories/UserRepository.php +++ b/app/Repositories/UserRepository.php @@ -6,6 +6,7 @@ use App\Http\Resources\UserResource; use App\Models\ExamUser; use App\Models\Setting; use App\Models\User; +use Illuminate\Database\Eloquent\Builder; class UserRepository extends BaseRepository { @@ -25,7 +26,10 @@ class UserRepository extends BaseRepository public function getDetail($id) { - $user = User::query()->with(['invitee_code'])->findOrFail($id, User::$commonFields); + $with = [ + 'inviter' => function (Builder $query) {return $query->select(User::$commonFields);} + ]; + $user = User::query()->with($with)->findOrFail($id, User::$commonFields); $userResource = new UserResource($user); $baseInfo = $userResource->response()->getData(true)['data']; diff --git a/database/migrations/2019_08_19_000000_create_failed_jobs_table.php b/database/migrations/2019_08_19_000000_create_failed_jobs_table.php deleted file mode 100644 index 6aa6d743..00000000 --- a/database/migrations/2019_08_19_000000_create_failed_jobs_table.php +++ /dev/null @@ -1,36 +0,0 @@ -id(); - $table->string('uuid')->unique(); - $table->text('connection'); - $table->text('queue'); - $table->longText('payload'); - $table->longText('exception'); - $table->timestamp('failed_at')->useCurrent(); - }); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::dropIfExists('failed_jobs'); - } -} diff --git a/database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php b/database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php deleted file mode 100644 index 3ce00023..00000000 --- a/database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php +++ /dev/null @@ -1,36 +0,0 @@ -bigIncrements('id'); - $table->morphs('tokenable'); - $table->string('name'); - $table->string('token', 64)->unique(); - $table->text('abilities')->nullable(); - $table->timestamp('last_used_at')->nullable(); - $table->timestamps(); - }); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::dropIfExists('personal_access_tokens'); - } -} diff --git a/database/migrations/2021_04_19_061650_create_exams_table.php b/database/migrations/2021_04_19_061650_create_exams_table.php deleted file mode 100644 index 09ae6026..00000000 --- a/database/migrations/2021_04_19_061650_create_exams_table.php +++ /dev/null @@ -1,40 +0,0 @@ -id(); - $table->string('name'); - $table->text('description')->nullable(); - $table->dateTime('begin')->nullable(); - $table->dateTime('end')->nullable(); - $table->integer('duration')->default(0); - $table->text('filters')->nullable(); - $table->text('indexes'); - $table->tinyInteger('status')->default(0); - $table->tinyInteger('is_discovered')->default(0); - $table->timestamps(); - }); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::dropIfExists('exams'); - } -} diff --git a/database/migrations/2021_04_19_062743_create_exam_progress_table.php b/database/migrations/2021_04_19_062743_create_exam_progress_table.php deleted file mode 100644 index dd091205..00000000 --- a/database/migrations/2021_04_19_062743_create_exam_progress_table.php +++ /dev/null @@ -1,38 +0,0 @@ -id(); - $table->integer('exam_user_id')->index(); - $table->integer('exam_id')->index(); - $table->integer('uid')->index(); - $table->integer('torrent_id'); - $table->integer('index'); - $table->bigInteger('value'); - $table->timestamps(); - $table->index('created_at'); - }); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::dropIfExists('exam_progress'); - } -} diff --git a/database/migrations/2021_04_24_084104_create_exam_users_table.php b/database/migrations/2021_04_24_084104_create_exam_users_table.php deleted file mode 100644 index 9e75b1c5..00000000 --- a/database/migrations/2021_04_24_084104_create_exam_users_table.php +++ /dev/null @@ -1,38 +0,0 @@ -id(); - $table->integer('uid')->index(); - $table->integer('exam_id')->index(); - $table->integer('status')->default(0); - $table->dateTime('begin')->nullable(); - $table->dateTime('end')->nullable(); - $table->text('progress')->nullable(); - $table->tinyInteger('is_done')->default(0); - $table->timestamps(); - }); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::dropIfExists('exam_users'); - } -} diff --git a/public/modtask.php b/public/modtask.php index 676659e7..8429c593 100644 --- a/public/modtask.php +++ b/public/modtask.php @@ -29,7 +29,7 @@ if ($action == "edituser") $class = intval($_POST["class"] ?? 0); $vip_added = ($_POST["vip_added"] == 'yes' ? 'yes' : 'no'); $vip_until = ($_POST["vip_until"] ? $_POST["vip_until"] : null); - + $warned = $_POST["warned"] ?? ''; $warnlength = intval($_POST["warnlength"] ?? 0); $warnpm = $_POST["warnpm"]; @@ -46,22 +46,23 @@ if ($action == "edituser") $forumpost = $_POST["forumpost"]; $chpassword = $_POST["chpassword"]; $passagain = $_POST["passagain"]; - + $supportlang = $_POST["supportlang"]; $support = $_POST["support"]; - $supportfor = $_POST["supportfor"]; - + $supportfor = $_POST["supportfor"]; + $moviepicker = $_POST["moviepicker"]; $pickfor = $_POST["pickfor"]; $stafffor = $_POST["staffduties"]; - + if (!is_valid_id($userid) || !is_valid_user_class($class)) stderr("Error", "Bad user ID or class ID."); if (get_user_class() <= $class) stderr("Error", "You have no permission to change user's class to ".get_user_class_name($class,false,false,true).". BTW, how do you get here?"); $res = sql_query("SELECT * FROM users WHERE id = ".sqlesc($userid)) or sqlerr(__FILE__, __LINE__); $arr = mysql_fetch_assoc($res) or puke(); - + $user = \App\Models\User::query()->findOrFail($userid); + $curenabled = $arr["enabled"]; $curparked = $arr["parked"]; $curuploadpos = $arr["uploadpos"]; @@ -69,7 +70,7 @@ if ($action == "edituser") $curforumpost = $arr["forumpost"]; $curclass = $arr["class"]; $curwarned = $arr["warned"]; - + $updateset[] = "stafffor = " . sqlesc($stafffor); $updateset[] = "pickfor = " . sqlesc($pickfor); $updateset[] = "picker = " . sqlesc($moviepicker); @@ -83,7 +84,8 @@ if ($action == "edituser") $updateset[] = "support = " . sqlesc($support); $updateset[] = "supportfor = " . sqlesc($supportfor); $updateset[] = "supportlang = ".sqlesc($supportlang); - + $banLog = []; + if(get_user_class()<=$cruprfmanage_class) { $modcomment = $arr["modcomment"]; @@ -152,7 +154,7 @@ if ($action == "edituser") $this_donated_usd = $donated - $arr["donated"]; $this_donated_cny = $donated_cny - $arr["donated_cny"]; $memo = sqlesc(htmlspecialchars($_POST["donation_memo"])); - + if ($donated != $arr['donated'] || $donated_cny != $arr['donated_cny']) { $added = sqlesc(date("Y-m-d H:i:s")); sql_query("INSERT INTO funds (usd, cny, user, added, memo) VALUES ($this_donated_usd, $this_donated_cny, $userid, $added, $memo)") or sqlerr(__FILE__, __LINE__); @@ -162,17 +164,17 @@ if ($action == "edituser") $updateset[] = "donor = " . sqlesc($donor); } - + if ($chpassword != "" AND $passagain != "") { unset($passupdate); $passupdate=false; - + if ($chpassword == $username OR strlen($chpassword) > 40 OR strlen($chpassword) < 6 OR $chpassword != $passagain) $passupdate=false; else $passupdate=true; } - + if (isset($passupdate) && $passupdate) { $sec = mksecret(); $passhash = md5($sec . $chpassword . $sec); @@ -205,7 +207,7 @@ if ($action == "edituser") sql_query("INSERT INTO messages (sender, receiver, subject, msg, added) VALUES (0, $userid, $subject, $msg, $added)") or sqlerr(__FILE__, __LINE__); $modcomment = date("Y-m-d") . " - VIP status changed by {$CURUSER['username']}. VIP added: ".$vip_added.($vip_added == 'yes' ? "; VIP until: ".$vip_until : "").".\n". $modcomment; } - + if ($warned && $curwarned != $warned) { $updateset[] = "warned = " . sqlesc($warned); @@ -229,7 +231,7 @@ if ($action == "edituser") $msg = sqlesc($lang_modtask_target[get_user_lang($userid)]['msg_you_are_warned_by'].$CURUSER['username']."." . ($warnpm ? $lang_modtask_target[get_user_lang($userid)]['msg_reason'].$warnpm : "")); $updateset[] = "warneduntil = null"; }else{ - $warneduntil = date("Y-m-d H:i:s",(strtotime(date("Y-m-d H:i:s")) + $warnlength * 604800)); + $warneduntil = date("Y-m-d H:i:s",(strtotime(date("Y-m-d H:i:s")) + $warnlength * 604800)); $dur = $warnlength . $lang_modtask_target[get_user_lang($userid)]['msg_week'] . ($warnlength > 1 ? $lang_modtask_target[get_user_lang($userid)]['msg_s'] : ""); $msg = sqlesc($lang_modtask_target[get_user_lang($userid)]['msg_you_are_warned_for'].$dur.$lang_modtask_target[get_user_lang($userid)]['msg_by'] . $CURUSER['username'] . "." . ($warnpm ? $lang_modtask_target[get_user_lang($userid)]['msg_reason'].$warnpm : "")); $modcomment = date("Y-m-d") . " - Warned for $dur by " . $CURUSER['username'] . ".\nReason: $warnpm.\n". $modcomment; @@ -253,7 +255,12 @@ if ($action == "edituser") sql_query("UPDATE users SET enabled='yes', leechwarn='no' WHERE id = ".sqlesc($userid)) or sqlerr(__FILE__, __LINE__); } } else { - $modcomment = date("Y-m-d") . " - Disabled by " . $CURUSER['username']. ".\n". $modcomment; + $modcomment = date("Y-m-d") . " - Disabled by " . $CURUSER['username']. ".\n". $modcomment; + $banLog = [ + 'uid' => $userid, + 'username' => $user->username, + 'reason' => nexus_trans('user.edit_ban_reason', [], $user->locale), + ]; } } if ($arr['noad'] != $noad){ @@ -266,7 +273,7 @@ if ($action == "edituser") } if ($privacy == "low" OR $privacy == "normal" OR $privacy == "strong") $updateset[] = "privacy = " . sqlesc($privacy); - + if (isset($_POST["resetkey"]) && $_POST["resetkey"] == "yes") { $newpasskey = md5($arr['username'].date("Y-m-d H:i:s").$arr['passhash']); @@ -328,12 +335,14 @@ if ($action == "edituser") $added = sqlesc(date("Y-m-d H:i:s")); sql_query("INSERT INTO messages (sender, receiver, subject, msg, added) VALUES (0, $userid, $subject, $msg, $added)") or sqlerr(__FILE__, __LINE__); } - } - - $updateset[] = "modcomment = " . sqlesc($modcomment); - - sql_query("UPDATE users SET " . implode(", ", $updateset) . " WHERE id=$userid") or sqlerr(__FILE__, __LINE__); + } + $updateset[] = "modcomment = " . sqlesc($modcomment); + + sql_query("UPDATE users SET " . implode(", ", $updateset) . " WHERE id=$userid") or sqlerr(__FILE__, __LINE__); + if (!empty($banLog)) { + \App\Models\UserBanLog::query()->insert($banLog); + } $returnto = htmlspecialchars($_POST["returnto"]); header("Location: " . get_protocol_prefix() . "$BASEURL/$returnto"); die; diff --git a/resources/lang/en/exam.php b/resources/lang/en/exam.php index b9ad1e55..6a254aba 100644 --- a/resources/lang/en/exam.php +++ b/resources/lang/en/exam.php @@ -17,4 +17,6 @@ return [ 'checkout_pass_message_content' => 'Congratulation! You have complete the exam: :exam_name in time(:begin ~ :end)', 'checkout_not_pass_message_subject' => 'Exam not pass, and account is banned!', 'checkout_not_pass_message_content' => 'You did not complete the exam: :exam_name in time(:begin ~ :end), and your account has be banned!', + 'ban_log_reason' => 'Not complete exam: :exam_name in time(:begin ~ :end)', + 'ban_user_modcomment' => 'Due to not complete exam: :exam_name(:begin ~ :end), ban by system', ]; diff --git a/resources/lang/en/user.php b/resources/lang/en/user.php new file mode 100644 index 00000000..b6eec675 --- /dev/null +++ b/resources/lang/en/user.php @@ -0,0 +1,5 @@ + 'Disable by administrator', +]; diff --git a/resources/lang/zh_CN/exam.php b/resources/lang/zh_CN/exam.php index f3613361..bda49eae 100644 --- a/resources/lang/zh_CN/exam.php +++ b/resources/lang/zh_CN/exam.php @@ -17,4 +17,6 @@ return [ 'checkout_pass_message_content' => '恭喜!你在规定时间内(:begin ~ :end)顺利完成了考核::exam_name。', 'checkout_not_pass_message_subject' => '考核未通过,账号被禁用!', 'checkout_not_pass_message_content' => '你在规定时间内(:begin ~ :end)未完成考核::exam_name,账号已被禁用。', + 'ban_log_reason' => '未完成考核::exam_name(:begin ~ :end)', + 'ban_user_modcomment' => '未完成考核: :exam_name(:begin ~ :end), 被系统禁用', ]; diff --git a/resources/lang/zh_CN/user.php b/resources/lang/zh_CN/user.php new file mode 100644 index 00000000..75dd8a61 --- /dev/null +++ b/resources/lang/zh_CN/user.php @@ -0,0 +1,5 @@ + '被管理人员禁用', +]; diff --git a/resources/lang/zh_TW/exam.php b/resources/lang/zh_TW/exam.php index 8123c9cb..32e554fe 100644 --- a/resources/lang/zh_TW/exam.php +++ b/resources/lang/zh_TW/exam.php @@ -17,4 +17,6 @@ return [ 'checkout_pass_message_content' => '恭喜!你在規定時間內(:begin ~ :end)順利完成了考核::exam_name。', 'checkout_not_pass_message_subject' => '考核未通過,賬號被禁用!', 'checkout_not_pass_message_content' => '你在規定時間內(:begin ~ :end)未完成考核::exam_name,賬號已被禁用。', + 'ban_log_reason' => '未完成考核::exam_name(:begin ~ :end)', + 'ban_user_modcomment' => '未完成考核: :exam_name(:begin ~ :end), 被系統禁用', ]; diff --git a/resources/lang/zh_TW/user.php b/resources/lang/zh_TW/user.php new file mode 100644 index 00000000..5c24285d --- /dev/null +++ b/resources/lang/zh_TW/user.php @@ -0,0 +1,5 @@ + '被管理人員禁用', +];