diff --git a/.env.example b/.env.example
index e020b3b8..d37e0183 100644
--- a/.env.example
+++ b/.env.example
@@ -62,4 +62,4 @@ GOOGLE_DRIVE_REFRESH_TOKEN=
GOOGLE_DRIVE_FOLDER_ID=
GEOIP2_DATABASE=
-EXAM_PROGRESS_UPDATE_PROBABILITY=60
+EXAM_PROGRESS_UPDATE_PROBABILITY=20
diff --git a/admin/src/utils/api.js b/admin/src/utils/api.js
index d38417a5..647ec5d8 100644
--- a/admin/src/utils/api.js
+++ b/admin/src/utils/api.js
@@ -84,6 +84,9 @@ const api = {
avoidExamUser: (id) => {
return axios.put('exam-users-avoid', {id});
},
+ recoverExamUser: (id) => {
+ return axios.put('exam-users-recover', {id});
+ },
storeExamUser: (params) => {
return axios.post('exam-users', params);
},
diff --git a/admin/src/views/user/detail.vue b/admin/src/views/user/detail.vue
index fb53be77..972777b2 100644
--- a/admin/src/views/user/detail.vue
+++ b/admin/src/views/user/detail.vue
@@ -125,6 +125,15 @@
Avoid
+
+
+ Recover
+
+
@@ -205,6 +214,12 @@ export default {
await fetchPageData()
}
+ const handleRecoverExam = async (id) => {
+ let res = await api.recoverExamUser(id)
+ ElMessage.success(res.msg)
+ await fetchPageData()
+ }
+
const handleAssignExam = async () => {
assignExam.value.open(id)
}
@@ -230,6 +245,7 @@ export default {
handleRemoveExam,
handleAvoidExam,
handleAssignExam,
+ handleRecoverExam,
handleEnableUser,
handleViewInviteInfo,
handleDisableUser,
diff --git a/app/Http/Controllers/ExamUserController.php b/app/Http/Controllers/ExamUserController.php
index 6b7db3ae..17db4588 100644
--- a/app/Http/Controllers/ExamUserController.php
+++ b/app/Http/Controllers/ExamUserController.php
@@ -99,4 +99,11 @@ class ExamUserController extends Controller
return $this->success($result, 'Avoid user exam success!');
}
+ public function recover(Request $request)
+ {
+ $request->validate(['id' => 'required']);
+ $result = $this->repository->recoverExamUser($request->id);
+ return $this->success($result, 'Recover user exam success!');
+ }
+
}
diff --git a/app/Models/ExamIndexInitValue.php b/app/Models/ExamIndexInitValue.php
new file mode 100644
index 00000000..64dcd653
--- /dev/null
+++ b/app/Models/ExamIndexInitValue.php
@@ -0,0 +1,10 @@
+findOrFail($id);
DB::transaction(function () use ($exam) {
- ExamUser::query()->where('exam_id', $exam->id)->delete();
- ExamProgress::query()->where('exam_id', $exam->id)->delete();
+ do {
+ $deleted = ExamUser::query()->where('exam_id', $exam->id)->limit(10000)->delete();
+ } while ($deleted > 0);
+ do {
+ $deleted = ExamProgress::query()->where('exam_id', $exam->id)->limit(10000)->delete();
+ } while ($deleted > 0);
$exam->delete();
});
return true;
@@ -232,8 +243,9 @@ class ExamRepository extends BaseRepository
$data['end'] = $end;
}
do_log("$logPrefix, data: " . nexus_json_encode($data));
- $result = $user->exams()->create($data);
- return $result;
+ $examUser = $user->exams()->create($data);
+ $this->initProgress($examUser, $user);
+ return $examUser;
}
public function listUser(array $params)
@@ -343,6 +355,41 @@ class ExamRepository extends BaseRepository
return true;
}
+ public function initProgress($examUser, $user = null)
+ {
+ if (!$examUser instanceof ExamUser) {
+ $examUser = ExamUser::query()->findOrFail((int)$examUser);
+ }
+ $exam = $examUser->exam;
+ if (!$user instanceof User) {
+ $user = $examUser->user()->select(['id', 'uploaded', 'downloaded', 'seedtime', 'leechtime', 'seedbonus'])->first();
+ }
+ $insert = [
+ 'uid' => $user->id,
+ 'exam_id' => $exam->id,
+ ];
+ foreach ($exam->indexes as $key => $index) {
+ if (!isset($index['checked']) || !$index['checked']) {
+ continue;
+ }
+ $insert['index'] = $index['index'];
+ if ($index['index'] == Exam::INDEX_UPLOADED) {
+ $insert['value'] = $user->uploaded;
+ } elseif ($index['index'] == Exam::INDEX_DOWNLOADED) {
+ $insert['value'] = $user->downloaded;
+ } elseif ($index['index'] == Exam::INDEX_SEED_BONUS) {
+ $insert['value'] = $user->seedbonus;
+ } elseif ($index['index'] == Exam::INDEX_SEED_TIME_AVERAGE) {
+ $insert['value'] = 0;
+ } else {
+ throw new \RuntimeException("Unknown index: {$index['index']}");
+ }
+ ExamIndexInitValue::query()->insert($insert);
+ do_log("insert: " . json_encode($insert));
+ }
+ return true;
+ }
+
public function getUserExamProgress($uid, $status = null, $with = ['exam', 'user'])
{
$logPrefix = "uid: $uid";
@@ -449,7 +496,9 @@ class ExamRepository extends BaseRepository
{
$examUser = ExamUser::query()->findOrFail($examUserId);
$result = DB::transaction(function () use ($examUser) {
- $examUser->progresses()->delete();
+ do {
+ $deleted = $examUser->progresses()->limit(10000)->delete();
+ } while ($deleted > 0);
return $examUser->delete();
});
return $result;
@@ -457,11 +506,18 @@ class ExamRepository extends BaseRepository
public function avoidExamUser(int $examUserId)
{
- $examUser = ExamUser::query()->findOrFail($examUserId);
+ $examUser = ExamUser::query()->where('status',ExamUser::STATUS_NORMAL)->findOrFail($examUserId);
$result = $examUser->update(['status' => ExamUser::STATUS_AVOIDED]);
return $result;
}
+ public function recoverExamUser(int $examUserId)
+ {
+ $examUser = ExamUser::query()->where('status',ExamUser::STATUS_AVOIDED)->findOrFail($examUserId);
+ $result = $examUser->update(['status' => ExamUser::STATUS_NORMAL]);
+ return $result;
+ }
+
public function cronjonAssign()
{
$exams = $this->listValid(null, Exam::DISCOVERED_YES);
@@ -523,17 +579,16 @@ class ExamRepository extends BaseRepository
// do_log("$currentLogPrefix, exam not match this user.");
// continue;
// }
- $insert[] = [
+ $insert = [
'uid' => $user->id,
'exam_id' => $exam->id,
'created_at' => $now,
'updated_at' => $now,
];
do_log("$currentLogPrefix, exam will be assigned to this user.");
- }
- if (!empty($insert)) {
- $result += count($insert);
- ExamUser::query()->insert($insert);
+ $examUser = ExamUser::query()->create($insert);
+ $this->initProgress($examUser, $user);
+ $result++;
}
}
return $result;
diff --git a/database/migrations/2021_06_11_014259_create_exam_index_init_values_table.php b/database/migrations/2021_06_11_014259_create_exam_index_init_values_table.php
new file mode 100644
index 00000000..51733d2b
--- /dev/null
+++ b/database/migrations/2021_06_11_014259_create_exam_index_init_values_table.php
@@ -0,0 +1,37 @@
+id();
+ $table->integer('uid')->index();
+ $table->integer('exam_user_id');
+ $table->integer('exam_id')->index();
+ $table->integer('index')->index();
+ $table->bigInteger('value');
+ $table->timestamps();
+ $table->unique(['exam_user_id', 'exam_id', 'index']);
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('exam_index_init_values');
+ }
+}
diff --git a/routes/api.php b/routes/api.php
index bec01c9d..013c0a56 100644
--- a/routes/api.php
+++ b/routes/api.php
@@ -50,6 +50,7 @@ Route::group(['middleware' => ['auth:sanctum', 'permission', 'locale']], functio
Route::resource('exam-users', \App\Http\Controllers\ExamUserController::class);
Route::put('exam-users-avoid', [\App\Http\Controllers\ExamUserController::class, 'avoid']);
+ Route::put('exam-users-recover', [\App\Http\Controllers\ExamUserController::class, 'recover']);
Route::get('dashboard/system-info', [\App\Http\Controllers\DashboardController::class, 'systemInfo']);
Route::get('dashboard/stat-data', [\App\Http\Controllers\DashboardController::class, 'statData']);