diff --git a/app/Models/BonusLogs.php b/app/Models/BonusLogs.php
index 22b69f6d..63c15887 100644
--- a/app/Models/BonusLogs.php
+++ b/app/Models/BonusLogs.php
@@ -36,6 +36,8 @@ class BonusLogs extends NexusModel
const BUSINESS_TYPE_BUY_CHANGE_USERNAME_CARD = 17;
const BUSINESS_TYPE_GIFT_MEDAL = 18;
const BUSINESS_TYPE_BUY_TORRENT = 19;
+ const BUSINESS_TYPE_TASK_NOT_PASS_DEDUCT = 20;
+ const BUSINESS_TYPE_TASK_PASS_REWARD = 21;
const BUSINESS_TYPE_ROLE_WORK_SALARY = 1000;
const BUSINESS_TYPE_TORRENT_BE_DOWNLOADED = 1001;
diff --git a/app/Models/Exam.php b/app/Models/Exam.php
index e5dd3147..0333467a 100644
--- a/app/Models/Exam.php
+++ b/app/Models/Exam.php
@@ -254,4 +254,32 @@ class Exam extends NexusModel
throw new \RuntimeException("Invalid recurring: $recurring");
}
+ public function getMessageSubjectTransKey(string $result): string
+ {
+ return match ($this->type) {
+ self::TYPE_EXAM => "exam.checkout_{$result}_message_subject_for_exam",
+ self::TYPE_TASK => "exam.checkout_{$result}_message_subject_for_task",
+ default => throw new \RuntimeException("Invalid type: " . $this->type)
+ };
+ }
+
+ public function getMessageContentTransKey(string $result): string
+ {
+ return match ($this->type) {
+ self::TYPE_EXAM => "exam.checkout_{$result}_message_content_for_exam",
+ self::TYPE_TASK => "exam.checkout_{$result}_message_content_for_task",
+ default => throw new \RuntimeException("Invalid type: " . $this->type)
+ };
+ }
+
+ public function isTypeExam(): bool
+ {
+ return $this->type == self::TYPE_EXAM;
+ }
+
+ public function isTypeTask(): bool
+ {
+ return $this->type == self::TYPE_TASK;
+ }
+
}
diff --git a/app/Models/User.php b/app/Models/User.php
index 55a480e1..eccddb2a 100644
--- a/app/Models/User.php
+++ b/app/Models/User.php
@@ -514,6 +514,11 @@ class User extends Authenticatable implements FilamentUser, HasName
return $this->hasMany(UserPermission::class, 'uid');
}
+ public function examAndTasks(): \Illuminate\Database\Eloquent\Relations\BelongsToMany
+ {
+ return $this->belongsToMany(Exam::class, "exam_users", "uid", "exam_id");
+ }
+
public function getAvatarAttribute($value)
{
if ($value) {
diff --git a/app/Repositories/ExamRepository.php b/app/Repositories/ExamRepository.php
index 61b9bcf7..27f342f3 100644
--- a/app/Repositories/ExamRepository.php
+++ b/app/Repositories/ExamRepository.php
@@ -2,6 +2,7 @@
namespace App\Repositories;
use App\Exceptions\NexusException;
+use App\Models\BonusLogs;
use App\Models\Exam;
use App\Models\ExamProgress;
use App\Models\ExamUser;
@@ -1100,11 +1101,13 @@ class ExamRepository extends BaseRepository
$result += $examUsers->count();
$now = Carbon::now()->toDateTimeString();
$examUserIdArr = $uidToDisable = $messageToSend = $userBanLog = $userModcommentUpdate = [];
+ $bonusLog = $userBonusCommentUpdate = $userBonusUpdate = $uidToUpdateBonus = [];
$examUserToInsert = [];
foreach ($examUsers as $examUser) {
$minId = $examUser->id;
$examUserIdArr[] = $examUser->id;
$uid = $examUser->uid;
+ clear_inbox_count_cache($uid);
/** @var Exam $exam */
$exam = $examUser->exam;
$currentLogPrefix = sprintf("$logPrefix, user: %s, exam: %s, examUser: %s", $uid, $examUser->exam_id, $examUser->id);
@@ -1119,48 +1122,95 @@ class ExamRepository extends BaseRepository
$locale = $examUser->user->locale;
if ($examUser->is_done) {
do_log("$currentLogPrefix, [is_done]");
- $subjectTransKey = 'exam.checkout_pass_message_subject';
- $msgTransKey = 'exam.checkout_pass_message_content';
- if (!empty($exam->recurring) && $this->isExamMatchUser($exam, $examUser->user)) {
- $examUserToInsert[] = [
- 'uid' => $examUser->user->id,
- 'exam_id' => $exam->id,
- 'begin' => $exam->getBeginForUser(),
- 'end' => $exam->getEndForUser(),
- 'created_at' => $now,
- 'updated_at' => $now,
- ];
+ $subjectTransKey = $exam->getMessageSubjectTransKey("pass");
+ $msgTransKey = $exam->getMessageContentTransKey("pass");
+ if ($exam->isTypeExam()) {
+ if (!empty($exam->recurring) && $this->isExamMatchUser($exam, $examUser->user)) {
+ $examUserToInsert[] = [
+ 'uid' => $examUser->user->id,
+ 'exam_id' => $exam->id,
+ 'begin' => $exam->getBeginForUser(),
+ 'end' => $exam->getEndForUser(),
+ 'created_at' => $now,
+ 'updated_at' => $now,
+ ];
+ }
+ } elseif ($exam->isTypeTask()) {
+ //reward bonus
+ if ($exam->success_reward_bonus > 0) {
+ $uidToUpdateBonus[] = $uid;
+ $bonusLog[] = [
+ "uid" => $uid,
+ "old_total_value" => $examUser->user->seedbonus,
+ "value" => $exam->success_reward_bonus,
+ "new_total_value" => $examUser->user->seedbonus + $exam->success_reward_bonus,
+ "business_type" => BonusLogs::BUSINESS_TYPE_TASK_PASS_REWARD,
+ ];
+ $userBonusComment = nexus_trans("exam.reward_bonus_comment", [
+ 'exam_name' => $exam->name,
+ 'begin' => $examUser->begin,
+ 'end' => $examUser->end,
+ 'success_reward_bonus' => $exam->success_reward_bonus,
+ ], $locale);
+ $userBonusCommentUpdate[] = sprintf("when `id` = %s then concat_ws('\n', '%s', bonuscomment)", $uid, $userBonusComment);
+ $userBonusUpdate[] = sprintf("when `id` = %s then seedbonus + %d", $uid, $exam->success_reward_bonus);
+ }
}
} else {
- do_log("$currentLogPrefix, [will be banned]");
- clear_user_cache($examUser->user->id, $examUser->user->passkey);
- $subjectTransKey = 'exam.checkout_not_pass_message_subject';
- $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);
- $userModcomment = sprintf('%s - %s', date('Y-m-d'), $userModcomment);
- $userModcommentUpdate[] = sprintf("when `id` = %s then concat_ws('\n', '%s', modcomment)", $uid, $userModcomment);
- $banLogReason = nexus_trans('exam.ban_log_reason', [
- 'exam_name' => $exam->name,
- 'begin' => $examUser->begin,
- 'end' => $examUser->end,
- ], $locale);
- $userBanLog[] = [
- 'uid' => $uid,
- 'username' => $examUser->user->username,
- 'reason' => $banLogReason,
- ];
+ do_log("$currentLogPrefix, [not_done]");
+ $subjectTransKey = $exam->getMessageSubjectTransKey("not_pass");
+ $msgTransKey = $exam->getMessageContentTransKey("not_pass");
+ if ($exam->isTypeExam()) {
+ //ban user
+ do_log("$currentLogPrefix, [will be banned]");
+ clear_user_cache($examUser->user->id, $examUser->user->passkey);
+ $uidToDisable[] = $uid;
+ $userModcomment = nexus_trans('exam.ban_user_modcomment', [
+ 'exam_name' => $exam->name,
+ 'begin' => $examUser->begin,
+ 'end' => $examUser->end
+ ], $locale);
+ $userModcomment = sprintf('%s - %s', date('Y-m-d'), $userModcomment);
+ $userModcommentUpdate[] = sprintf("when `id` = %s then concat_ws('\n', '%s', modcomment)", $uid, $userModcomment);
+ $banLogReason = nexus_trans('exam.ban_log_reason', [
+ 'exam_name' => $exam->name,
+ 'begin' => $examUser->begin,
+ 'end' => $examUser->end,
+ ], $locale);
+ $userBanLog[] = [
+ 'uid' => $uid,
+ 'username' => $examUser->user->username,
+ 'reason' => $banLogReason,
+ ];
+ } elseif ($exam->isTypeTask()) {
+ //deduct bonus
+ if ($exam->fail_deduct_bonus > 0) {
+ $uidToUpdateBonus[] = $uid;
+ $bonusLog[] = [
+ "uid" => $uid,
+ "old_total_value" => $examUser->user->seedbonus,
+ "value" => -1*$exam->fail_deduct_bonus,
+ "new_total_value" => $examUser->user->seedbonus - $exam->fail_deduct_bonus,
+ "business_type" => BonusLogs::BUSINESS_TYPE_TASK_NOT_PASS_DEDUCT,
+ ];
+ $userBonusComment = nexus_trans("exam.deduct_bonus_comment", [
+ 'exam_name' => $exam->name,
+ 'begin' => $examUser->begin,
+ 'end' => $examUser->end,
+ 'fail_deduct_bonus' => $exam->fail_deduct_bonus,
+ ], $locale);
+ $userBonusCommentUpdate[] = sprintf("when `id` = %s then concat_ws('\n', '%s', bonuscomment)", $uid, $userBonusComment);
+ $userBonusUpdate[] = sprintf("when `id` = %s then seedbonus - %d", $uid, $exam->fail_deduct_bonus);
+ }
+ }
}
$subject = nexus_trans($subjectTransKey, [], $locale);
$msg = nexus_trans($msgTransKey, [
'exam_name' => $exam->name,
'begin' => $examUser->begin,
- 'end' => $examUser->end
+ 'end' => $examUser->end,
+ 'success_reward_bonus' => $exam->success_reward_bonus,
+ 'fail_deduct_bonus' => $exam->fail_deduct_bonus,
], $locale);
$messageToSend[] = [
'receiver' => $uid,
@@ -1169,7 +1219,7 @@ class ExamRepository extends BaseRepository
'msg' => $msg
];
}
- DB::transaction(function () use ($uidToDisable, $messageToSend, $examUserIdArr, $examUserToInsert, $userBanLog, $userModcommentUpdate, $userTable, $logPrefix) {
+ DB::transaction(function () use ($uidToDisable, $messageToSend, $examUserIdArr, $examUserToInsert, $userBanLog, $userModcommentUpdate, $userBonusUpdate, $userBonusCommentUpdate, $bonusLog, $uidToUpdateBonus, $userTable, $logPrefix) {
ExamUser::query()->whereIn('id', $examUserIdArr)->update(['status' => ExamUser::STATUS_FINISHED]);
do {
$deleted = ExamProgress::query()->whereIn('exam_user_id', $examUserIdArr)->limit(10000)->delete();
@@ -1191,6 +1241,18 @@ class ExamRepository extends BaseRepository
if (!empty($examUserToInsert)) {
ExamUser::query()->insert($examUserToInsert);
}
+ if (!empty($userBonusUpdate)) {
+ $uidStr = implode(', ', $uidToUpdateBonus);
+ $sql = sprintf(
+ "update %s set seedbonus = case %s, bonuscomment = case %s end where id in (%s)",
+ $userTable, implode(' ', $userBonusUpdate), implode(",", $userBonusCommentUpdate), $uidStr
+ );
+ $updateResult = DB::update($sql);
+ do_log(sprintf("$logPrefix, update %s users: %s seedbonus, sql: %s, updateResult: %s", count($uidToUpdateBonus), $uidStr, $sql, $updateResult));
+ }
+ if (!empty($bonusLog)) {
+ BonusLogs::query()->insert($bonusLog);
+ }
});
}
return $result;
diff --git a/include/functions.php b/include/functions.php
index 98f16b11..54241436 100644
--- a/include/functions.php
+++ b/include/functions.php
@@ -2670,6 +2670,7 @@ else {
[]:
'.$lang_functions['text_attended'].'', $attendance->points, $CURUSER['attendance_card']); }else{ printf(' %s', $lang_functions['text_attendance']);}?>
[]
+ []
[]: where('inviter', $CURUSER['id'])->where('invitee', '')->where('expired_at', '>', now())->count())?>
= \App\Models\User::getAccessAdminClassMin()) printf('[%s]', nexus_env('FILAMENT_PATH', 'nexusphp'), $lang_functions['text_management_system'])?>
diff --git a/public/task.php b/public/task.php
new file mode 100644
index 00000000..319197f1
--- /dev/null
+++ b/public/task.php
@@ -0,0 +1,125 @@
+where('type', \App\Models\Exam::TYPE_TASK)->where("status", \App\Models\Exam::STATUS_ENABLED);
+$total = (clone $query)->count();
+$perPage = 20;
+list($paginationTop, $paginationBottom, $limit, $offset) = pager($perPage, $total, "?");
+$rows = (clone $query)->offset($offset)->take($perPage)->orderBy('id', 'desc')->get();
+$title = nexus_trans('exam.type_task');
+$columnNameLabel = nexus_trans('label.name');
+$columnIndexLabel = nexus_trans('exam.index');
+$columnBeginTimeLabel = nexus_trans('label.begin');
+$columnEndTimeLabel = nexus_trans('label.end');
+$columnDurationLabel = nexus_trans('label.duration');
+$columnRecurringLabel = nexus_trans('exam.recurring');
+$columnTargetUserLabel = nexus_trans('label.exam.filter_formatted');
+$columnDescLabel = nexus_trans('label.description');
+$columnSuccessRewardLabel = nexus_trans('exam.success_reward_bonus');
+$columnFailDeductLabel = nexus_trans('exam.fail_deduct_bonus');
+$columnDescriptionDeductLabel = nexus_trans('label.description');
+$columnClaimLabel = nexus_trans('exam.action_claim_task');
+
+$header = '
| $columnNameLabel | +$columnIndexLabel | +$columnBeginTimeLabel | +$columnEndTimeLabel | +$columnTargetUserLabel | +$columnSuccessRewardLabel | +$columnFailDeductLabel | +$columnDescriptionDeductLabel | +$columnClaimLabel | +%s | ', $row->name); + $columns[] = sprintf('%s | ', $row->indexFormatted); + $columns[] = sprintf('%s | ', $row->getBeginForUser()); + $columns[] = sprintf('%s | ', $row->getEndForUser()); + $columns[] = sprintf('%s | ', $row->filterFormatted); + $columns[] = sprintf('%s | ', number_format($row->success_reward_bonus)); + $columns[] = sprintf('%s | ', number_format($row->fail_deduct_bonus)); + $columns[] = sprintf('%s | ', $row->description); + $columns[] = sprintf('%s | ', $claimAction); + $table .= sprintf('