From 64a1f2bb0cc51b290074d4b4e40d55aac62ca9ca Mon Sep 17 00:00:00 2001 From: xiaomlove Date: Wed, 19 Jan 2022 23:54:55 +0800 Subject: [PATCH] medal management --- admin/src/App.vue | 3 + admin/src/router/index.js | 10 + admin/src/utils/api.js | 23 +- admin/src/utils/index.js | 2 + admin/src/views/medal/form.vue | 162 ++++++++ admin/src/views/medal/index.vue | 151 ++++++++ admin/src/views/user/detail.vue | 63 ++- app/Console/Commands/Test.php | 9 +- app/Http/Controllers/MedalController.php | 103 +++++ app/Http/Controllers/UserMedalController.php | 106 +++++ app/Http/Resources/MedalResource.php | 31 ++ app/Http/Resources/UserResource.php | 1 + app/Models/BonusLogs.php | 2 + app/Models/Medal.php | 39 ++ app/Models/User.php | 15 + app/Models/UserMedal.php | 8 + app/Repositories/BonusRepository.php | 108 ++++-- app/Repositories/MedalRepository.php | 54 +++ app/Repositories/UserRepository.php | 10 +- .../2022_01_06_023153_create_medals_table.php | 38 ++ ..._01_06_153905_create_user_medals_table.php | 34 ++ include/constants.php | 2 +- include/functions.php | 20 +- lang/chs/lang_mybonus.php | 1 + lang/chs/lang_userdetails.php | 1 + lang/cht/lang_mybonus.php | 1 + lang/cht/lang_userdetails.php | 1 + lang/en/lang_mybonus.php | 1 + lang/en/lang_userdetails.php | 1 + nexus/Database/NexusDB.php | 25 +- public/details.php | 5 +- public/forums.php | 18 +- public/mybonus.php | 364 ++++++++++++------ public/userdetails.php | 7 + resources/lang/en/medal.php | 9 + resources/lang/zh_CN/bonus.php | 5 + resources/lang/zh_CN/medal.php | 9 + resources/lang/zh_TW/medal.php | 9 + routes/api.php | 2 + 39 files changed, 1282 insertions(+), 171 deletions(-) create mode 100644 admin/src/views/medal/form.vue create mode 100644 admin/src/views/medal/index.vue create mode 100644 app/Http/Controllers/MedalController.php create mode 100644 app/Http/Controllers/UserMedalController.php create mode 100644 app/Http/Resources/MedalResource.php create mode 100644 app/Models/Medal.php create mode 100644 app/Models/UserMedal.php create mode 100644 app/Repositories/MedalRepository.php create mode 100644 database/migrations/2022_01_06_023153_create_medals_table.php create mode 100644 database/migrations/2022_01_06_153905_create_user_medals_table.php create mode 100644 resources/lang/en/medal.php create mode 100644 resources/lang/zh_CN/bonus.php create mode 100644 resources/lang/zh_CN/medal.php create mode 100644 resources/lang/zh_TW/medal.php diff --git a/admin/src/App.vue b/admin/src/App.vue index 2e586d1c..b11e5504 100644 --- a/admin/src/App.vue +++ b/admin/src/App.vue @@ -38,6 +38,9 @@ Exam user + + Medal + Setting diff --git a/admin/src/router/index.js b/admin/src/router/index.js index c928e27e..a8bb045f 100644 --- a/admin/src/router/index.js +++ b/admin/src/router/index.js @@ -54,6 +54,16 @@ const router = createRouter({ name: 'agent-allow-form', component: () => import('../views/agent-allow/form.vue') }, + { + path: '/medal', + name: 'medal', + component: () => import('../views/medal/index.vue') + }, + { + path: '/medal-form', + name: 'medal-form', + component: () => import('../views/medal/form.vue') + }, { path: '/setting', name: 'setting', diff --git a/admin/src/utils/api.js b/admin/src/utils/api.js index 647ec5d8..05509879 100644 --- a/admin/src/utils/api.js +++ b/admin/src/utils/api.js @@ -72,6 +72,24 @@ const api = { deleteExam: (id) => { return axios.delete('exams/' + id); }, + + listMedal: (params = {}) => { + return axios.get('medals', {params: params}); + }, + storeMedal: (params = {}) => { + return axios.post('medals', params); + }, + updateMedal: (id, params = {}) => { + return axios.put('medals/' + id, params); + }, + getMedal: (id) => { + return axios.get('medals/' + id); + }, + deleteMedal: (id) => { + return axios.delete('medals/' + id); + }, + + listClass: (params = {}) => { return axios.get('user-classes', {params: params}); }, @@ -107,7 +125,10 @@ const api = { }, listSystemInfo: () => { return axios.get('dashboard/system-info') - } + }, + removeUserMedal: (id) => { + return axios.delete('user-medals/' + id); + }, } diff --git a/admin/src/utils/index.js b/admin/src/utils/index.js index 15fe508e..bdaf6fa8 100644 --- a/admin/src/utils/index.js +++ b/admin/src/utils/index.js @@ -47,4 +47,6 @@ export const pathMap = { 'exam-form': 'Exam form', 'exam-user': 'Exam user', 'setting': "Setting", + 'medal': 'Medal', + 'medal-form': 'Medal form', } diff --git a/admin/src/views/medal/form.vue b/admin/src/views/medal/form.vue new file mode 100644 index 00000000..263f808e --- /dev/null +++ b/admin/src/views/medal/form.vue @@ -0,0 +1,162 @@ + + + + + diff --git a/admin/src/views/medal/index.vue b/admin/src/views/medal/index.vue new file mode 100644 index 00000000..71d2cd3e --- /dev/null +++ b/admin/src/views/medal/index.vue @@ -0,0 +1,151 @@ + + + + + diff --git a/admin/src/views/user/detail.vue b/admin/src/views/user/detail.vue index 972777b2..eb6cfc2c 100644 --- a/admin/src/views/user/detail.vue +++ b/admin/src/views/user/detail.vue @@ -153,12 +153,62 @@ + + + + + + + + + + + + + + + + + + + + + - @@ -240,6 +290,12 @@ export default { const handleResetPassword = async () => { resetPassword.value.open(id) } + + const handleRemoveUserMedal = async (id) => { + let res = await api.removeUserMedal(id) + ElMessage.success(res.msg) + await fetchPageData() + } return { ...toRefs(state), handleRemoveExam, @@ -252,6 +308,7 @@ export default { handleGetModComment, handleResetPassword, fetchPageData, + handleRemoveUserMedal, assignExam, viewInviteInfo, disableUser, @@ -271,10 +328,10 @@ export default { text-align: left; tr { th { - padding-bottom: 10px; + padding-bottom: 4px; } td { - padding: 10px 0; + padding: 4px 0; } } } diff --git a/app/Console/Commands/Test.php b/app/Console/Commands/Test.php index 727604b1..6b428194 100644 --- a/app/Console/Commands/Test.php +++ b/app/Console/Commands/Test.php @@ -7,12 +7,14 @@ use App\Models\Exam; use App\Models\ExamProgress; use App\Models\ExamUser; use App\Models\HitAndRun; +use App\Models\Medal; use App\Models\SearchBox; use App\Models\Snatch; use App\Models\User; use App\Repositories\ExamRepository; use App\Repositories\SearchBoxRepository; use App\Repositories\TorrentRepository; +use App\Repositories\UserRepository; use Carbon\Carbon; use GeoIp2\Database\Reader; use Illuminate\Console\Command; @@ -55,11 +57,8 @@ class Test extends Command */ public function handle() { - $user = User::query()->first(); - $user->update([ - 'page' => DB::raw('dddd') - ]); - dd(last_query()); + $rep = new UserRepository(); + $r = $rep->getDetail(1); } } diff --git a/app/Http/Controllers/MedalController.php b/app/Http/Controllers/MedalController.php new file mode 100644 index 00000000..651b53bf --- /dev/null +++ b/app/Http/Controllers/MedalController.php @@ -0,0 +1,103 @@ +repository = $repository; + } + + /** + * Display a listing of the resource. + * + * @param Request $request + * @return array + */ + public function index(Request $request) + { + $result = $this->repository->getList($request->all()); + $resource = MedalResource::collection($result); + $resource->additional([ + 'page_title' => nexus_trans('medal.admin.list.page_title'), + ]); + return $this->success($resource); + } + + /** + * Store a newly created resource in storage. + * + * @param \Illuminate\Http\Request $request + * @return array + */ + public function store(Request $request) + { + $rules = [ + 'name' => 'required|string', + 'price' => 'required|integer|min:1', + 'image_large' => 'required|url', + 'image_small' => 'required|url', + 'duration' => 'nullable|integer|min:-1', + ]; + $request->validate($rules); + $result = $this->repository->store($request->all()); + $resource = new MedalResource($result); + return $this->success($resource); + } + + /** + * Display the specified resource. + * + * @param int $id + * @return array + */ + public function show($id) + { + $result = $this->repository->getDetail($id); + $resource = new MedalResource($result); + return $this->success($resource); + } + + /** + * Update the specified resource in storage. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return array + */ + public function update(Request $request, $id) + { + $rules = [ + 'name' => 'required|string', + 'price' => 'required|integer|min:1', + 'image_large' => 'required|url', + 'image_small' => 'required|url', + 'duration' => 'nullable|integer|min:-1', + ]; + $request->validate($rules); + $result = $this->repository->update($request->all(), $id); + $resource = new MedalResource($result); + return $this->success($resource); + } + + /** + * Remove the specified resource from storage. + * + * @param int $id + * @return array + */ + public function destroy($id) + { + $result = $this->repository->delete($id); + return $this->success($result, 'Delete medal success!'); + } + + +} diff --git a/app/Http/Controllers/UserMedalController.php b/app/Http/Controllers/UserMedalController.php new file mode 100644 index 00000000..fa7d63fe --- /dev/null +++ b/app/Http/Controllers/UserMedalController.php @@ -0,0 +1,106 @@ +repository = $repository; + } + + /** + * Display a listing of the resource. + * + * @param Request $request + * @return array + */ + public function index(Request $request) + { + $result = $this->repository->getList($request->all()); + $resource = MedalResource::collection($result); + $resource->additional([ + 'page_title' => nexus_trans('medal.admin.list.page_title'), + ]); + return $this->success($resource); + } + + /** + * Store a newly created resource in storage. + * + * @param \Illuminate\Http\Request $request + * @return array + */ + public function store(Request $request) + { + $rules = [ + 'name' => 'required|string', + 'price' => 'required|integer|min:1', + 'image_large' => 'required|url', + 'image_small' => 'required|url', + 'duration' => 'nullable|integer|min:-1', + ]; + $request->validate($rules); + $result = $this->repository->store($request->all()); + $resource = new MedalResource($result); + return $this->success($resource); + } + + /** + * Display the specified resource. + * + * @param int $id + * @return array + */ + public function show($id) + { + $result = $this->repository->getDetail($id); + $resource = new MedalResource($result); + return $this->success($resource); + } + + /** + * Update the specified resource in storage. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return array + */ + public function update(Request $request, $id) + { + $rules = [ + 'name' => 'required|string', + 'price' => 'required|integer|min:1', + 'image_large' => 'required|url', + 'image_small' => 'required|url', + 'duration' => 'nullable|integer|min:-1', + ]; + $request->validate($rules); + $result = $this->repository->update($request->all(), $id); + $resource = new MedalResource($result); + return $this->success($resource); + } + + /** + * Remove the specified resource from storage. + * + * @param int $id + * @return array + */ + public function destroy($id) + { + $userMedal = UserMedal::query()->findOrFail($id); + $result = $userMedal->delete(); + return $this->success($result, 'Remove user medal success!'); + } + + +} diff --git a/app/Http/Resources/MedalResource.php b/app/Http/Resources/MedalResource.php new file mode 100644 index 00000000..043d9aee --- /dev/null +++ b/app/Http/Resources/MedalResource.php @@ -0,0 +1,31 @@ + $this->id, + 'name' => $this->name, + 'get_type' => $this->get_type, + 'get_type_text' => $this->getTypeText, + 'image_large' => $this->image_large, + 'image_small' => $this->image_small, + 'price' => $this->price, + 'duration' => $this->duration, + 'description' => $this->description, + 'expire_at' => $this->whenPivotLoaded('user_medals', function () {return $this->pivot->expire_at;}), + 'user_medal_id' => $this->whenPivotLoaded('user_medals', function () {return $this->pivot->id;}), + ]; + } +} diff --git a/app/Http/Resources/UserResource.php b/app/Http/Resources/UserResource.php index b5282ee2..9fe3c56f 100644 --- a/app/Http/Resources/UserResource.php +++ b/app/Http/Resources/UserResource.php @@ -34,6 +34,7 @@ class UserResource extends JsonResource 'leechtime' => $this->leechtime, 'leechtime_text' => mkprettytime($this->leechtime), 'inviter' => new UserResource($this->whenLoaded('inviter')), + 'valid_medals' => MedalResource::collection($this->whenLoaded('valid_medals')), ]; if ($request->routeIs('user.me')) { $out['downloaded_human'] = mksize($this->downloaded); diff --git a/app/Models/BonusLogs.php b/app/Models/BonusLogs.php index 97c225e3..8216ecd0 100644 --- a/app/Models/BonusLogs.php +++ b/app/Models/BonusLogs.php @@ -12,9 +12,11 @@ class BonusLogs extends NexusModel const DEFAULT_BONUS_CANCEL_ONE_HIT_AND_RUN = 10000; const BUSINESS_TYPE_CANCEL_HIT_AND_RUN = 1; + const BUSINESS_TYPE_BUY_MEDAL = 2; public static $businessTypes = [ self::BUSINESS_TYPE_CANCEL_HIT_AND_RUN => ['text' => 'Cancel H&R'], + self::BUSINESS_TYPE_BUY_MEDAL => ['text' => 'Buy medal'], ]; public static function getBonusForCancelHitAndRun() diff --git a/app/Models/Medal.php b/app/Models/Medal.php new file mode 100644 index 00000000..be7dde27 --- /dev/null +++ b/app/Models/Medal.php @@ -0,0 +1,39 @@ + ['text' => 'Exchange'], + self::GET_TYPE_GRANT => ['text' => 'Grant'], + ]; + + protected $fillable = ['name', 'description', 'image_large', 'image_small', 'price', 'duration', 'get_type']; + + public $timestamps = true; + + public function getGetTypeTextAttribute($value): string + { + return self::$getTypeText[$this->get_type]['text'] ?? ''; + } + + public function users(): \Illuminate\Database\Eloquent\Relations\BelongsToMany + { + return $this->belongsToMany(User::class, 'user_medals', 'medal_id', 'uid')->withTimestamps(); + } + + public function valid_users(): \Illuminate\Database\Eloquent\Relations\BelongsToMany + { + return $this->users()->where(function ($query) { + $query->whereNull('user_medals.expire_at')->orWhere('user_medals.expire_at', '>=', Carbon::now()); + }); + } + +} diff --git a/app/Models/User.php b/app/Models/User.php index cf27d234..2342e7ac 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -3,6 +3,7 @@ namespace App\Models; use App\Http\Middleware\Locale; +use Carbon\Carbon; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; @@ -263,6 +264,20 @@ class User extends Authenticatable return $this->hasMany(HitAndRun::class, 'uid'); } + public function medals(): \Illuminate\Database\Eloquent\Relations\BelongsToMany + { + return $this->belongsToMany(Medal::class, 'user_medals', 'uid', 'medal_id') + ->withPivot(['id', 'expire_at']) + ->withTimestamps(); + } + + public function valid_medals(): \Illuminate\Database\Eloquent\Relations\BelongsToMany + { + return $this->medals()->where(function ($query) { + $query->whereNull('user_medals.expire_at')->orWhere('user_medals.expire_at', '>=', Carbon::now()); + }); + } + public function getAvatarAttribute($value) { if ($value) { diff --git a/app/Models/UserMedal.php b/app/Models/UserMedal.php new file mode 100644 index 00000000..123e32d0 --- /dev/null +++ b/app/Models/UserMedal.php @@ -0,0 +1,8 @@ +seedbonus < $requireBonus) { - do_log("user: $uid, bonus: {$user->seedbonus} < requireBonus: $requireBonus", 'error'); - throw new \LogicException("User bonus point not enough."); - } - $result = NexusDB::transaction(function () use ($user, $hitAndRun, $requireBonus) { - $oldUserBonus = $user->seedbonus; - $newUserBonus = bcsub($oldUserBonus, $requireBonus); - $log = "user: {$user->id}, hitAndRun: {$hitAndRun->id}, requireBonus: $requireBonus, oldUserBonus: $oldUserBonus, newUserBonus: $newUserBonus"; - do_log($log); - $affectedRows = NexusDB::table($user->getTable()) - ->where('id', $user->id) - ->where('seedbonus', $oldUserBonus) - ->update(['seedbonus' => $newUserBonus]); - if ($affectedRows != 1) { - do_log("update user seedbonus affected rows != 1, query: " . last_query(), 'error'); - throw new \RuntimeException("Update user seedbonus fail."); - } + NexusDB::transaction(function () use ($user, $hitAndRun, $requireBonus) { $comment = nexus_trans('hr.bonus_cancel_comment', [ 'now' => Carbon::now()->toDateTimeString(), 'bonus' => $requireBonus, ], $user->locale); $comment = addslashes($comment); do_log("comment: $comment"); + + $this->consumeUserBonus($user, $requireBonus, BonusLogs::BUSINESS_TYPE_CANCEL_HIT_AND_RUN, "$comment(H&R ID: {$hitAndRun->id})"); + $hitAndRun->update([ 'status' => HitAndRun::STATUS_PARDONED, - 'comment' => new Expression("concat(comment, '\n$comment')"), + 'comment' => NexusDB::raw("concat(comment, '\n$comment')"), ]); - $bonusLog = [ - 'business_type' => BonusLogs::BUSINESS_TYPE_CANCEL_HIT_AND_RUN, - 'uid' => $user->id, - 'old_total_value' => $oldUserBonus, - 'value' => $requireBonus, - 'new_total_value' => $newUserBonus, - 'comment' => "$comment(H&R ID: {$hitAndRun->id})", - ]; - BonusLogs::query()->insert($bonusLog); - do_log("bonusLog: " . json_encode($bonusLog)); - return true; }); - return $result; + return true; } @@ -74,11 +49,11 @@ class BonusRepository extends BaseRepository $tableName = (new User())->getTable(); $result = 0; do { - $affectedRows = DB::table($tableName) + $affectedRows = NexusDB::table($tableName) ->whereNull('seed_points') ->limit($size) ->update([ - 'seed_points' => DB::raw('seed_points = seedbonus') + 'seed_points' => NexusDB::raw('seed_points = seedbonus') ]); $result += $affectedRows; do_log("affectedRows: $affectedRows, query: " . last_query()); @@ -88,4 +63,67 @@ class BonusRepository extends BaseRepository } + public function consumeToBuyMedal($uid, $medalId): bool + { + $user = User::query()->findOrFail($uid); + $medal = Medal::query()->findOrFail($medalId); + $exists = $user->valid_medals()->where('medal_id', $medalId)->exists(); + do_log(last_query()); + if ($exists) { + throw new \LogicException("user: $uid already own this medal: $medalId."); + } + $requireBonus = $medal->price; + NexusDB::transaction(function () use ($user, $medal, $requireBonus) { + $comment = nexus_trans('bonus.comment_buy_medal', [ + 'bonus' => $requireBonus, + 'medal_name' => $medal->name, + ], $user->locale); + $comment = addslashes($comment); + do_log("comment: $comment"); + $this->consumeUserBonus($user, $requireBonus, BonusLogs::BUSINESS_TYPE_BUY_MEDAL, "$comment(medal ID: {$medal->id})"); + $expireAt = null; + if ($medal->duration > 0) { + $expireAt = Carbon::now()->addDays($medal->duration)->toDateTimeString(); + } + $user->medals()->attach([$medal->id => ['expire_at' => $expireAt]]); + + }); + + return true; + + } + + private function consumeUserBonus($user, $requireBonus, $logBusinessType, $logComment = '') + { + if ($user->seedbonus < $requireBonus) { + do_log("user: {$user->id}, bonus: {$user->seedbonus} < requireBonus: $requireBonus", 'error'); + throw new \LogicException("User bonus point not enough."); + } + NexusDB::transaction(function () use ($user, $requireBonus, $logBusinessType, $logComment) { + $oldUserBonus = $user->seedbonus; + $newUserBonus = bcsub($oldUserBonus, $requireBonus); + $log = "user: {$user->id}, requireBonus: $requireBonus, oldUserBonus: $oldUserBonus, newUserBonus: $newUserBonus, logBusinessType: $logBusinessType, logComment: $logComment"; + do_log($log); + $affectedRows = NexusDB::table($user->getTable()) + ->where('id', $user->id) + ->where('seedbonus', $oldUserBonus) + ->update(['seedbonus' => $newUserBonus]); + if ($affectedRows != 1) { + do_log("update user seedbonus affected rows != 1, query: " . last_query(), 'error'); + throw new \RuntimeException("Update user seedbonus fail."); + } + $bonusLog = [ + 'business_type' => $logBusinessType, + 'uid' => $user->id, + 'old_total_value' => $oldUserBonus, + 'value' => $requireBonus, + 'new_total_value' => $newUserBonus, + 'comment' => $logComment, + ]; + BonusLogs::query()->insert($bonusLog); + do_log("bonusLog: " . nexus_json_encode($bonusLog)); + }); + } + + } diff --git a/app/Repositories/MedalRepository.php b/app/Repositories/MedalRepository.php new file mode 100644 index 00000000..801ae8fc --- /dev/null +++ b/app/Repositories/MedalRepository.php @@ -0,0 +1,54 @@ +getSortFieldAndType($params); + $query->orderBy($sortField, $sortType); + return $query->paginate(); + } + + public function store(array $params) + { + return Medal::query()->create($params); + } + + public function update(array $params, $id) + { + $medal = Medal::query()->findOrFail($id); + $medal->update($params); + return $medal; + } + + + public function getDetail($id) + { + return Medal::query()->findOrFail($id); + } + + /** + * delete a medal, also will delete all user medal. + * + * @param $id + * @return bool + */ + public function delete($id): bool + { + $medal = Medal::query()->findOrFail($id); + NexusDB::transaction(function () use ($medal) { + do { + $deleted = UserMedal::query()->where('medal_id', $medal->id)->limit(10000)->delete(); + } while ($deleted > 0); + $medal->delete(); + }); + return true; + } + +} diff --git a/app/Repositories/UserRepository.php b/app/Repositories/UserRepository.php index 86aaadc1..3a56010b 100644 --- a/app/Repositories/UserRepository.php +++ b/app/Repositories/UserRepository.php @@ -30,14 +30,15 @@ class UserRepository extends BaseRepository public function getDetail($id) { $with = [ - 'inviter' => function ($query) {return $query->select(User::$commonFields);} + 'inviter' => function ($query) {return $query->select(User::$commonFields);}, + 'valid_medals' ]; $user = User::query()->with($with)->findOrFail($id, User::$commonFields); $userResource = new UserResource($user); $baseInfo = $userResource->response()->getData(true)['data']; $examRep = new ExamRepository(); - $examProgress = $examRep->getUserExamProgress($id, null, ['exam']); + $examProgress = $examRep->getUserExamProgress($id, null); if ($examProgress) { $examResource = new ExamUserResource($examProgress); $examInfo = $examResource->response()->getData(true)['data']; @@ -45,6 +46,8 @@ class UserRepository extends BaseRepository $examInfo = null; } + + return [ 'base_info' => $baseInfo, 'exam_info' => $examInfo, @@ -156,4 +159,7 @@ class UserRepository extends BaseRepository $user = User::query()->findOrFail($id, ['modcomment']); return $user->modcomment; } + + + } diff --git a/database/migrations/2022_01_06_023153_create_medals_table.php b/database/migrations/2022_01_06_023153_create_medals_table.php new file mode 100644 index 00000000..e04707fe --- /dev/null +++ b/database/migrations/2022_01_06_023153_create_medals_table.php @@ -0,0 +1,38 @@ +id(); + $table->string('name'); + $table->integer('get_type'); + $table->text('description')->nullable(); + $table->string('image_large')->nullable(); + $table->string('image_small')->nullable(); + $table->integer('price')->default(0); + $table->integer('duration')->default(0); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('medals'); + } +} diff --git a/database/migrations/2022_01_06_153905_create_user_medals_table.php b/database/migrations/2022_01_06_153905_create_user_medals_table.php new file mode 100644 index 00000000..029038d9 --- /dev/null +++ b/database/migrations/2022_01_06_153905_create_user_medals_table.php @@ -0,0 +1,34 @@ +id(); + $table->integer('uid')->index(); + $table->integer('medal_id')->index(); + $table->dateTime('expire_at')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('user_medals'); + } +} diff --git a/include/constants.php b/include/constants.php index bb965d2c..4e98d93b 100644 --- a/include/constants.php +++ b/include/constants.php @@ -1,6 +1,6 @@ enable_ad()) $commentad = $Advertisement->get_ad('comment'); + + $uidArr = array_unique(array_column($rows, 'user')); + $neededColumns = array('id', 'noad', 'class', 'enabled', 'privacy', 'avatar', 'signature', 'uploaded', 'downloaded', 'last_access', 'username', 'donor', 'leechwarn', 'warned', 'title'); + $userInfoArr = \App\Models\User::query()->with(['valid_medals'])->find($uidArr, $neededColumns)->keyBy('id'); + foreach ($rows as $row) { - $userRow = get_user_row($row['user']); +// $userRow = get_user_row($row['user']); + $userInfo = $userInfoArr->get($row['user']); + $userRow = $userInfo->toArray(); if ($count>=1) { if ($Advertisement->enable_ad()){ @@ -2931,7 +2938,7 @@ function commenttable($rows, $type, $parent_id, $review = false) } } print("
#" . $row["id"] . "  ".$lang_functions['text_by'].""); - print(get_username($row["user"],false,true,true,false,false,true)); + print(build_medal_image($userInfo->valid_medals, 20) . get_username($row["user"],false,true,true,false,false,true)); print("  ".$lang_functions['text_at']."".gettime($row["added"]). ($row["editedby"] && get_user_class() >= $commanage_class ? " - [".$lang_functions['text_view_original']."]" : "") . "\"Top\"  
"); $avatar = ($CURUSER["avatars"] == "yes" ? htmlspecialchars(trim($userRow["avatar"])) : ""); @@ -5259,4 +5266,13 @@ function msgalert($url, $text, $bgcolor = "red") print("


"); } +function build_medal_image(\Illuminate\Support\Collection $medals, $maxHeight = 200): string +{ + $medalImages = []; + foreach ($medals as $medal) { + $medalImages[] = sprintf('', $medal->image_large, $medal->name, $maxHeight); + } + return implode('', $medalImages); +} + ?> diff --git a/lang/chs/lang_mybonus.php b/lang/chs/lang_mybonus.php index 70319d9d..aeac7735 100644 --- a/lang/chs/lang_mybonus.php +++ b/lang/chs/lang_mybonus.php @@ -126,6 +126,7 @@ $lang_mybonus = array 'text_cancel_hr_title' => 'H&R 消除', 'text_cancel_hr_label' => '输入要消除的 H&R ID:', 'text_success_cancel_hr' => "成功消除了一个 H&R。", + 'text_success_buy_medal' => '成功购买该勋章。', ); ?> diff --git a/lang/chs/lang_userdetails.php b/lang/chs/lang_userdetails.php index d2271580..705e43e4 100644 --- a/lang/chs/lang_userdetails.php +++ b/lang/chs/lang_userdetails.php @@ -147,5 +147,6 @@ $lang_userdetails = array 'text_no_ad_until_note' => "时间格式为'年年年年-月月-日日 时时:分分:秒秒'。无广告待遇结束的时间。", 'disable_user_migrated' => '启用或禁用用户请到管理后台操作', 'text_user_id'=> "用户ID/UID", + 'row_medal' => '勋章', ); ?> diff --git a/lang/cht/lang_mybonus.php b/lang/cht/lang_mybonus.php index 4d160f0b..601a8f02 100644 --- a/lang/cht/lang_mybonus.php +++ b/lang/cht/lang_mybonus.php @@ -126,6 +126,7 @@ $lang_mybonus = array 'text_cancel_hr_title' => 'H&R 消除', 'text_cancel_hr_label' => '輸入要消除的 H&R ID:', 'text_success_cancel_hr' => "成功消除了一個 H&R。", + 'text_success_buy_medal' => '成功購買該勛章。', ); ?> diff --git a/lang/cht/lang_userdetails.php b/lang/cht/lang_userdetails.php index 8dcfd182..ce118821 100644 --- a/lang/cht/lang_userdetails.php +++ b/lang/cht/lang_userdetails.php @@ -147,5 +147,6 @@ $lang_userdetails = array 'text_no_ad_until_note' => "時間格式為'年年年年-月月-日日 時時:分分:秒秒'。無廣告待遇結束的時間。", 'disable_user_migrated' => '啟用或禁用用戶請到管理後臺操作', 'text_user_id'=> "用戶ID/UID", + 'row_medal' => '勛章', ); ?> diff --git a/lang/en/lang_mybonus.php b/lang/en/lang_mybonus.php index c36cc7c1..6ebbcdae 100644 --- a/lang/en/lang_mybonus.php +++ b/lang/en/lang_mybonus.php @@ -126,6 +126,7 @@ where
  • A is an intermediate variable
  • Ti is the i< 'text_cancel_hr_title' => 'H&R cancel', 'text_cancel_hr_label' => 'Type in H&R ID:', 'text_success_cancel_hr' => "Success cancel one H&R.", + 'text_success_buy_medal' => 'Success buy the medal.', ); ?> diff --git a/lang/en/lang_userdetails.php b/lang/en/lang_userdetails.php index 73c34e5f..a4582707 100644 --- a/lang/en/lang_userdetails.php +++ b/lang/en/lang_userdetails.php @@ -147,5 +147,6 @@ $lang_userdetails = array 'text_no_ad_until_note' => "Time format is YYYY-MM-DD hh:mm:ss. The time until when the user can turn ads off.", 'disable_user_migrated' => 'Enable or disable use please go to the new management system.', 'text_user_id'=> "User ID", + 'row_medal' => 'Medal', ); ?> diff --git a/nexus/Database/NexusDB.php b/nexus/Database/NexusDB.php index 2dffb4d1..e52ead96 100644 --- a/nexus/Database/NexusDB.php +++ b/nexus/Database/NexusDB.php @@ -3,6 +3,8 @@ namespace Nexus\Database; use Illuminate\Database\Capsule\Manager as Capsule; +use Illuminate\Database\Query\Expression; +use Illuminate\Support\Facades\DB; class NexusDB { @@ -227,17 +229,34 @@ class NexusDB public static function schema(): \Illuminate\Database\Schema\Builder { - return Capsule::schema(self::ELOQUENT_CONNECTION_NAME); + if (IN_NEXUS) { + return Capsule::schema(self::ELOQUENT_CONNECTION_NAME); + } + throw new \RuntimeException('can not call this when not in nexus.'); } public static function table($table): \Illuminate\Database\Query\Builder { - return Capsule::table($table); + if (IN_NEXUS) { + return Capsule::table($table); + } + return DB::table($table); + } + + public static function raw($value): \Illuminate\Database\Query\Expression + { + if (IN_NEXUS) { + return new Expression($value); + } + return DB::raw($value); } public static function transaction(\Closure $callback, $attempts = 1) { - return Capsule::connection(self::ELOQUENT_CONNECTION_NAME)->transaction($callback, $attempts); + if (IN_NEXUS) { + return Capsule::connection(self::ELOQUENT_CONNECTION_NAME)->transaction($callback, $attempts); + } + return DB::transaction($callback, $attempts); } public static function getMysqlColumnInfo($table, $column) diff --git a/public/details.php b/public/details.php index f59ef9b3..2deb80bf 100644 --- a/public/details.php +++ b/public/details.php @@ -38,6 +38,7 @@ if (!$row) { ) { permissiondenied(); } else { + $owner = \App\Models\User::query()->with(['valid_medals'])->findOrFail($row['owner']); $torrentRep = new \App\Repositories\TorrentRepository(); $torrentUpdate = []; if (!empty($_GET["hit"])) { @@ -83,10 +84,10 @@ if (!$row) { if (get_user_class() < $viewanonymous_class) $uprow = "".$lang_details['text_anonymous'].""; else - $uprow = "".$lang_details['text_anonymous']." (" . get_username($row['owner'], false, true, true, false, false, true) . ")"; + $uprow = "".$lang_details['text_anonymous']." (" . build_medal_image($owner->valid_medals, 20) . get_username($row['owner'], false, true, true, false, false, true) . ")"; } else { - $uprow = (isset($row['owner']) ? get_username($row['owner'], false, true, true, false, false, true) : "".$lang_details['text_unknown'].""); + $uprow = (isset($row['owner']) ? build_medal_image($owner->valid_medals, 20) . get_username($row['owner'], false, true, true, false, false, true) : "".$lang_details['text_unknown'].""); } if ($CURUSER["id"] == $row["owner"]) diff --git a/public/forums.php b/public/forums.php index c86d5489..5f751c84 100644 --- a/public/forums.php +++ b/public/forums.php @@ -624,13 +624,22 @@ if ($action == "viewtopic") begin_frame(); $pc = mysql_num_rows($res); + $allPosts = $uidArr = []; + while ($arr = mysql_fetch_assoc($res)) { + $allPosts[] = $arr; + $uidArr[$arr['userid']] = 1; + } + $uidArr = array_keys($uidArr); + unset($arr); + $neededColumns = array('id', 'noad', 'class', 'enabled', 'privacy', 'avatar', 'signature', 'uploaded', 'downloaded', 'last_access', 'username', 'donor', 'leechwarn', 'warned', 'title'); + $userInfoArr = \App\Models\User::query()->with(['valid_medals'])->find($uidArr, $neededColumns)->keyBy('id'); $pn = 0; $lpr = get_last_read_post_id($topicid); if ($Advertisement->enable_ad()) $forumpostad=$Advertisement->get_ad('forumpost'); - while ($arr = mysql_fetch_assoc($res)) + foreach ($allPosts as $arr) { if ($pn>=1) { @@ -648,7 +657,10 @@ if ($action == "viewtopic") //---- Get poster details - $arr2 = get_user_row($posterid); +// $arr2 = get_user_row($posterid); + $userInfo = $userInfoArr->get($posterid); + $arr2 = $userInfo->toArray(); + $uploaded = mksize($arr2["uploaded"]); $downloaded = mksize($arr2["downloaded"]); $ratio = get_ratio($arr2['id']); @@ -662,7 +674,7 @@ if ($action == "viewtopic") $avatar = ($CURUSER["avatars"] == "yes" ? htmlspecialchars($arr2["avatar"]) : ""); $uclass = get_user_class_image($arr2["class"]); - $by = get_username($posterid,false,true,true,false,false,true); + $by = build_medal_image($userInfo->valid_medals, 20) . get_username($posterid,false,true,true,false,false,true); if (!$avatar) $avatar = "pic/default_avatar.png"; diff --git a/public/mybonus.php b/public/mybonus.php index 375bc229..23c227bc 100644 --- a/public/mybonus.php +++ b/public/mybonus.php @@ -6,104 +6,223 @@ require(get_langfile_path("",true)); loggedinorreturn(); parked(); -function bonusarray($option){ +function bonusarray($option = 0){ global $onegbupload_bonus,$fivegbupload_bonus,$tengbupload_bonus,$oneinvite_bonus,$customtitle_bonus,$vipstatus_bonus, $basictax_bonus, $taxpercentage_bonus, $bonusnoadpoint_advertisement, $bonusnoadtime_advertisement; global $lang_mybonus; - $bonus = array(); - switch ($option) - { - case 1: {//1.0 GB Uploaded - $bonus['points'] = $onegbupload_bonus; - $bonus['art'] = 'traffic'; - $bonus['menge'] = 1073741824; - $bonus['name'] = $lang_mybonus['text_uploaded_one']; - $bonus['description'] = $lang_mybonus['text_uploaded_note']; - break; - } - case 2: {//5.0 GB Uploaded - $bonus['points'] = $fivegbupload_bonus; - $bonus['art'] = 'traffic'; - $bonus['menge'] = 5368709120; - $bonus['name'] = $lang_mybonus['text_uploaded_two']; - $bonus['description'] = $lang_mybonus['text_uploaded_note']; - break; - } - case 3: {//10.0 GB Uploaded - $bonus['points'] = $tengbupload_bonus; - $bonus['art'] = 'traffic'; - $bonus['menge'] = 10737418240; - $bonus['name'] = $lang_mybonus['text_uploaded_three']; - $bonus['description'] = $lang_mybonus['text_uploaded_note']; - break; - } - case 4: {//Invite - $bonus['points'] = $oneinvite_bonus; - $bonus['art'] = 'invite'; - $bonus['menge'] = 1; - $bonus['name'] = $lang_mybonus['text_buy_invite']; - $bonus['description'] = $lang_mybonus['text_buy_invite_note']; - break; - } - case 5: {//Custom Title - $bonus['points'] = $customtitle_bonus; - $bonus['art'] = 'title'; - $bonus['menge'] = 0; - $bonus['name'] = $lang_mybonus['text_custom_title']; - $bonus['description'] = $lang_mybonus['text_custom_title_note']; - break; - } - case 6: {//VIP Status - $bonus['points'] = $vipstatus_bonus; - $bonus['art'] = 'class'; - $bonus['menge'] = 0; - $bonus['name'] = $lang_mybonus['text_vip_status']; - $bonus['description'] = $lang_mybonus['text_vip_status_note']; - break; - } - case 7: {//Bonus Gift - $bonus['points'] = 25; - $bonus['art'] = 'gift_1'; - $bonus['menge'] = 0; - $bonus['name'] = $lang_mybonus['text_bonus_gift']; - $bonus['description'] = $lang_mybonus['text_bonus_gift_note']; - if ($basictax_bonus || $taxpercentage_bonus){ - $onehundredaftertax = 100 - $taxpercentage_bonus - $basictax_bonus; - $bonus['description'] .= "

    ".$lang_mybonus['text_system_charges_receiver']."".($basictax_bonus ? $basictax_bonus.$lang_mybonus['text_tax_bonus_point'].add_s($basictax_bonus).($taxpercentage_bonus ? $lang_mybonus['text_tax_plus'] : "") : "").($taxpercentage_bonus ? $taxpercentage_bonus.$lang_mybonus['text_percent_of_transfered_amount'] : "")."".$lang_mybonus['text_as_tax'].$onehundredaftertax.$lang_mybonus['text_tax_example_note']; - } - break; - } - case 8: { - $bonus['points'] = $bonusnoadpoint_advertisement; - $bonus['art'] = 'noad'; - $bonus['menge'] = $bonusnoadtime_advertisement * 86400; - $bonus['name'] = $bonusnoadtime_advertisement.$lang_mybonus['text_no_advertisements']; - $bonus['description'] = $lang_mybonus['text_no_advertisements_note']; - break; - } - case 9: { - $bonus['points'] = 1000; - $bonus['art'] = 'gift_2'; - $bonus['menge'] = 0; - $bonus['name'] = $lang_mybonus['text_charity_giving']; - $bonus['description'] = $lang_mybonus['text_charity_giving_note']; - break; - } - case 10: { - $bonus['points'] = \App\Models\BonusLogs::getBonusForCancelHitAndRun(); - $bonus['art'] = 'cancel_hr'; - $bonus['menge'] = 0; - $bonus['name'] = $lang_mybonus['text_cancel_hr_title']; - $bonus['description'] = '

    + + $results = []; + //1.0 GB Uploaded + $bonus = array(); + $bonus['points'] = $onegbupload_bonus; + $bonus['art'] = 'traffic'; + $bonus['menge'] = 1073741824; + $bonus['name'] = $lang_mybonus['text_uploaded_one']; + $bonus['description'] = $lang_mybonus['text_uploaded_note']; + $results[] = $bonus; + + //5.0 GB Uploaded + $bonus = array(); + $bonus['points'] = $fivegbupload_bonus; + $bonus['art'] = 'traffic'; + $bonus['menge'] = 5368709120; + $bonus['name'] = $lang_mybonus['text_uploaded_two']; + $bonus['description'] = $lang_mybonus['text_uploaded_note']; + $results[] = $bonus; + + + //10.0 GB Uploaded + $bonus = array(); + $bonus['points'] = $tengbupload_bonus; + $bonus['art'] = 'traffic'; + $bonus['menge'] = 10737418240; + $bonus['name'] = $lang_mybonus['text_uploaded_three']; + $bonus['description'] = $lang_mybonus['text_uploaded_note']; + $results[] = $bonus; + + //Invite + $bonus = array(); + $bonus['points'] = $oneinvite_bonus; + $bonus['art'] = 'invite'; + $bonus['menge'] = 1; + $bonus['name'] = $lang_mybonus['text_buy_invite']; + $bonus['description'] = $lang_mybonus['text_buy_invite_note']; + + //Custom Title + $bonus = array(); + $bonus['points'] = $customtitle_bonus; + $bonus['art'] = 'title'; + $bonus['menge'] = 0; + $bonus['name'] = $lang_mybonus['text_custom_title']; + $bonus['description'] = $lang_mybonus['text_custom_title_note']; + $results[] = $bonus; + + + //VIP Status + $bonus = array(); + $bonus['points'] = $vipstatus_bonus; + $bonus['art'] = 'class'; + $bonus['menge'] = 0; + $bonus['name'] = $lang_mybonus['text_vip_status']; + $bonus['description'] = $lang_mybonus['text_vip_status_note']; + $results[] = $bonus; + + //Bonus Gift + $bonus = array(); + $bonus['points'] = 25; + $bonus['art'] = 'gift_1'; + $bonus['menge'] = 0; + $bonus['name'] = $lang_mybonus['text_bonus_gift']; + $bonus['description'] = $lang_mybonus['text_bonus_gift_note']; + if ($basictax_bonus || $taxpercentage_bonus){ + $onehundredaftertax = 100 - $taxpercentage_bonus - $basictax_bonus; + $bonus['description'] .= "

    ".$lang_mybonus['text_system_charges_receiver']."".($basictax_bonus ? $basictax_bonus.$lang_mybonus['text_tax_bonus_point'].add_s($basictax_bonus).($taxpercentage_bonus ? $lang_mybonus['text_tax_plus'] : "") : "").($taxpercentage_bonus ? $taxpercentage_bonus.$lang_mybonus['text_percent_of_transfered_amount'] : "")."".$lang_mybonus['text_as_tax'].$onehundredaftertax.$lang_mybonus['text_tax_example_note']; + } + $results[] = $bonus; + + + //No ad for 15 days + $bonus = array(); + $bonus['points'] = $bonusnoadpoint_advertisement; + $bonus['art'] = 'noad'; + $bonus['menge'] = $bonusnoadtime_advertisement * 86400; + $bonus['name'] = $bonusnoadtime_advertisement.$lang_mybonus['text_no_advertisements']; + $bonus['description'] = $lang_mybonus['text_no_advertisements_note']; + $results[] = $bonus; + + //Donate + $bonus = array(); + $bonus['points'] = 1000; + $bonus['art'] = 'gift_2'; + $bonus['menge'] = 0; + $bonus['name'] = $lang_mybonus['text_charity_giving']; + $bonus['description'] = $lang_mybonus['text_charity_giving_note']; + $results[] = $bonus; + + + //Cancel hit and run + $bonus = array(); + $bonus['points'] = \App\Models\BonusLogs::getBonusForCancelHitAndRun(); + $bonus['art'] = 'cancel_hr'; + $bonus['menge'] = 0; + $bonus['name'] = $lang_mybonus['text_cancel_hr_title']; + $bonus['description'] = '

    ' . $lang_mybonus['text_cancel_hr_label'] . '

    '; - break; - } - default: break; - } - return $bonus; + $results[] = $bonus; + + //Buy medal + $medals = \App\Models\Medal::query()->get(); + foreach ($medals as $medal) { + $results[] = [ + 'points' => $medal->price, + 'art' => 'buy_medal', + 'menge' => 0, + 'name' => $medal->name, + 'description' => sprintf('%s', $medal->description, $medal->id), + 'medal_id' => $medal->id, + ]; + } + + return $results; + +// +// switch ($option) +// { +// case 1: {//1.0 GB Uploaded +// $bonus['points'] = $onegbupload_bonus; +// $bonus['art'] = 'traffic'; +// $bonus['menge'] = 1073741824; +// $bonus['name'] = $lang_mybonus['text_uploaded_one']; +// $bonus['description'] = $lang_mybonus['text_uploaded_note']; +// break; +// } +// case 2: {//5.0 GB Uploaded +// $bonus['points'] = $fivegbupload_bonus; +// $bonus['art'] = 'traffic'; +// $bonus['menge'] = 5368709120; +// $bonus['name'] = $lang_mybonus['text_uploaded_two']; +// $bonus['description'] = $lang_mybonus['text_uploaded_note']; +// break; +// } +// case 3: {//10.0 GB Uploaded +// $bonus['points'] = $tengbupload_bonus; +// $bonus['art'] = 'traffic'; +// $bonus['menge'] = 10737418240; +// $bonus['name'] = $lang_mybonus['text_uploaded_three']; +// $bonus['description'] = $lang_mybonus['text_uploaded_note']; +// break; +// } +// case 4: {//Invite +// $bonus['points'] = $oneinvite_bonus; +// $bonus['art'] = 'invite'; +// $bonus['menge'] = 1; +// $bonus['name'] = $lang_mybonus['text_buy_invite']; +// $bonus['description'] = $lang_mybonus['text_buy_invite_note']; +// break; +// } +// case 5: {//Custom Title +// $bonus['points'] = $customtitle_bonus; +// $bonus['art'] = 'title'; +// $bonus['menge'] = 0; +// $bonus['name'] = $lang_mybonus['text_custom_title']; +// $bonus['description'] = $lang_mybonus['text_custom_title_note']; +// break; +// } +// case 6: {//VIP Status +// $bonus['points'] = $vipstatus_bonus; +// $bonus['art'] = 'class'; +// $bonus['menge'] = 0; +// $bonus['name'] = $lang_mybonus['text_vip_status']; +// $bonus['description'] = $lang_mybonus['text_vip_status_note']; +// break; +// } +// case 7: {//Bonus Gift +// $bonus['points'] = 25; +// $bonus['art'] = 'gift_1'; +// $bonus['menge'] = 0; +// $bonus['name'] = $lang_mybonus['text_bonus_gift']; +// $bonus['description'] = $lang_mybonus['text_bonus_gift_note']; +// if ($basictax_bonus || $taxpercentage_bonus){ +// $onehundredaftertax = 100 - $taxpercentage_bonus - $basictax_bonus; +// $bonus['description'] .= "

    ".$lang_mybonus['text_system_charges_receiver']."".($basictax_bonus ? $basictax_bonus.$lang_mybonus['text_tax_bonus_point'].add_s($basictax_bonus).($taxpercentage_bonus ? $lang_mybonus['text_tax_plus'] : "") : "").($taxpercentage_bonus ? $taxpercentage_bonus.$lang_mybonus['text_percent_of_transfered_amount'] : "")."".$lang_mybonus['text_as_tax'].$onehundredaftertax.$lang_mybonus['text_tax_example_note']; +// } +// break; +// } +// case 8: { +// $bonus['points'] = $bonusnoadpoint_advertisement; +// $bonus['art'] = 'noad'; +// $bonus['menge'] = $bonusnoadtime_advertisement * 86400; +// $bonus['name'] = $bonusnoadtime_advertisement.$lang_mybonus['text_no_advertisements']; +// $bonus['description'] = $lang_mybonus['text_no_advertisements_note']; +// break; +// } +// case 9: { +// $bonus['points'] = 1000; +// $bonus['art'] = 'gift_2'; +// $bonus['menge'] = 0; +// $bonus['name'] = $lang_mybonus['text_charity_giving']; +// $bonus['description'] = $lang_mybonus['text_charity_giving_note']; +// break; +// } +// case 10: { +// $bonus['points'] = \App\Models\BonusLogs::getBonusForCancelHitAndRun(); +// $bonus['art'] = 'cancel_hr'; +// $bonus['menge'] = 0; +// $bonus['name'] = $lang_mybonus['text_cancel_hr_title']; +// $bonus['description'] = '

    +// ' . $lang_mybonus['text_cancel_hr_label'] . ' +// +//

    '; +// break; +// } +// default: break; +// } +// return $bonus; } +$allBonus = bonusarray(); + if ($bonus_tweak == "disable" || $bonus_tweak == "disablesave") stderr($lang_mybonus['std_sorry'],$lang_mybonus['std_karma_system_disabled'].($bonus_tweak == "disablesave" ? "".$lang_mybonus['std_points_active']."" : ""),false); @@ -129,6 +248,8 @@ if (isset($do)) { $msg = $lang_mybonus['text_success_charity']; elseif ($do == "cancel_hr") $msg = $lang_mybonus['text_success_cancel_hr']; + elseif ($do == "buy_medal") + $msg = $lang_mybonus['text_success_buy_medal']; else $msg = ''; } @@ -150,42 +271,44 @@ print("".$lang_mybonus['col_option']. "".$lang_mybonus['col_points']."". "".$lang_mybonus['col_trade']."". ""); -for ($i=1; $i <=10; $i++) + + +for ($i=0; $i < count($allBonus); $i++) { - $bonusarray = bonusarray($i); + $bonusarray = $allBonus[$i]; if ( - ($i == 7 && $bonusgift_bonus == 'no') - || ($i == 8 && ($enablead_advertisement == 'no' || $bonusnoad_advertisement == 'no')) - || ($i == 10 && !\App\Models\HitAndRun::getIsEnabled()) + ($bonusarray['art'] == 'gift_1' && $bonusgift_bonus == 'no') + || ($bonusarray['art'] == 'noad' && ($enablead_advertisement == 'no' || $bonusnoad_advertisement == 'no')) + || ($bonusarray['art'] == 'cancel_hr' && !\App\Models\HitAndRun::getIsEnabled()) ) { continue; } print(""); print("
    "); - print("".$i.""); - if ($i==5){ //for Custom Title! - $otheroption_title = ""; - print("

    ".$bonusarray['name']."

    ".$bonusarray['description']."

    ".$lang_mybonus['text_enter_titile'].$otheroption_title.$lang_mybonus['text_click_exchange']."".number_format($bonusarray['points']).""); + print("".($i + 1).""); + if ($bonusarray['art'] == 'invite'){ //for Custom Title! + $otheroption_title = ""; + print("

    ".$bonusarray['name']."

    ".$bonusarray['description']."

    ".$lang_mybonus['text_enter_titile'].$otheroption_title.$lang_mybonus['text_click_exchange']."".number_format($bonusarray['points']).""); } - elseif ($i==7){ //for Give A Karma Gift + elseif ($bonusarray['art'] == 'gift_1'){ //for Give A Karma Gift $otheroption = "
    ".$lang_mybonus['text_username']."".$lang_mybonus['text_to_be_given']."".$lang_mybonus['text_karma_points']."
    ".$lang_mybonus['text_message']."
    "; print("

    ".$bonusarray['name']."

    ".$bonusarray['description']."

    ".$lang_mybonus['text_enter_receiver_name']."
    $otheroption".$lang_mybonus['text_min']."25
    ".$lang_mybonus['text_max']."10,000"); } - elseif ($i==9){ //charity giving + elseif ($bonusarray['art'] == 'gift_2'){ //charity giving $otheroption = "
    ".$lang_mybonus['text_ratio_below']."".$lang_mybonus['text_and_downloaded_above']." 10 GB".$lang_mybonus['text_to_be_given']."".$lang_mybonus['text_karma_points']."
    "; print("

    ".$bonusarray['name']."

    ".$bonusarray['description']."

    ".$lang_mybonus['text_select_receiver_ratio']."
    $otheroption".$lang_mybonus['text_min']."1,000
    ".$lang_mybonus['text_max']."50,000"); } - else{ //for VIP or Upload + else { //for VIP or Upload print("

    ".$bonusarray['name']."

    ".$bonusarray['description']."".number_format($bonusarray['points']).""); } if($CURUSER['seedbonus'] >= $bonusarray['points']) { - if ($i==7){ + if ($bonusarray['art'] == 'gift_1'){ print(""); } - elseif ($i==8){ + elseif ($bonusarray['art'] == 'noad'){ if ($enablenoad_advertisement == 'yes' && get_user_class() >= $noad_advertisement) print(""); elseif (strtotime($CURUSER['noaduntil']) >= TIMENOW) @@ -195,26 +318,26 @@ for ($i=1; $i <=10; $i++) else print(""); } - elseif ($i==9){ + elseif ($bonusarray['art'] == 'gift_2'){ print(""); } - elseif($i==4) + elseif($bonusarray['art'] == 'invite') { if(get_user_class() < $buyinvite_class) print(""); else print(""); } - elseif ($i==6) + elseif ($bonusarray['art'] == 'class') { if (get_user_class() >= UC_VIP) print(""); else print(""); } - elseif ($i==5) + elseif ($bonusarray['art'] == 'title') print(""); - else + elseif ($bonusarray['art'] == 'traffic') { if ($CURUSER['downloaded'] > 0){ if ($CURUSER['uploaded'] > $dlamountlimit_bonus * 1073741824)//Uploaded amount reach limit @@ -226,7 +349,9 @@ for ($i=1; $i <=10; $i++) print(""); } else print(""); - } + } else { + print(""); + } } else { @@ -323,15 +448,14 @@ print($lang_mybonus['text_howto_get_karma_five'].$uploadtorrent_bonus.$lang_mybo getMessage(), 'error'); stderr('Error', "Something wrong...", false, false); } + } elseif ($art == 'buy_medal') { + if (empty($_POST['medal_id'])) { + stderr("Error","Invalid Medal ID: " . ($_POST['medal_id'] ?? ''), false, false); + } + try { + $bonusRep = new \App\Repositories\BonusRepository(); + $bonusRep->consumeToBuyMedal($userid, $_POST['medal_id']); + nexus_redirect("" . get_protocol_prefix() . "$BASEURL/mybonus.php?do=buy_medal"); + } catch (\Exception $exception) { + do_log($exception->getMessage(), 'error'); + stderr('Error', "Something wrong...", false, false); + } } } } diff --git a/public/userdetails.php b/public/userdetails.php index 18c84f70..cae9b88f 100644 --- a/public/userdetails.php +++ b/public/userdetails.php @@ -28,6 +28,8 @@ else if ($user["status"] == "pending") stderr($lang_userdetails['std_sorry'], $lang_userdetails['std_user_not_confirmed']); +$userInfo = \App\Models\User::query()->with(['valid_medals'])->findOrFail($user['id']); + if ($user['added'] == "0000-00-00 00:00:00" || $user['added'] == null) $joindate = $lang_userdetails['text_not_available']; else @@ -271,6 +273,11 @@ tr_small($lang_userdetails['row_donated'], "$".htmlspecialchars($user['donated'] if ($user["avatar"]) tr_small($lang_userdetails['row_avatar'], return_avatar_image(htmlspecialchars(trim($user["avatar"]))), 1); + +if ($userInfo->valid_medals->isNotEmpty()) { + tr_small($lang_userdetails['row_medal'], build_medal_image($userInfo->valid_medals), 1); +} + $uclass = get_user_class_image($user["class"]); $utitle = get_user_class_name($user["class"],false,false,true); $uclassImg = "\"".get_user_class_name($user["class"],false,false,true)."\" ".($user['title']!=="" ? " ".htmlspecialchars(trim($user["title"]))."" : ""); diff --git a/resources/lang/en/medal.php b/resources/lang/en/medal.php new file mode 100644 index 00000000..eb712b18 --- /dev/null +++ b/resources/lang/en/medal.php @@ -0,0 +1,9 @@ + [ + 'list' => [ + 'page_title' => 'Medal list' + ] + ] +]; diff --git a/resources/lang/zh_CN/bonus.php b/resources/lang/zh_CN/bonus.php new file mode 100644 index 00000000..994148fc --- /dev/null +++ b/resources/lang/zh_CN/bonus.php @@ -0,0 +1,5 @@ + '花费 :bonus 魔力购买了 :medal_name', +]; diff --git a/resources/lang/zh_CN/medal.php b/resources/lang/zh_CN/medal.php new file mode 100644 index 00000000..32cbbc7f --- /dev/null +++ b/resources/lang/zh_CN/medal.php @@ -0,0 +1,9 @@ + [ + 'list' => [ + 'page_title' => '勋章列表' + ] + ] +]; diff --git a/resources/lang/zh_TW/medal.php b/resources/lang/zh_TW/medal.php new file mode 100644 index 00000000..492d0101 --- /dev/null +++ b/resources/lang/zh_TW/medal.php @@ -0,0 +1,9 @@ + [ + 'list' => [ + 'page_title' => '勛章列表' + ] + ] +]; diff --git a/routes/api.php b/routes/api.php index 4cd5fb55..a0fe149d 100644 --- a/routes/api.php +++ b/routes/api.php @@ -60,6 +60,8 @@ Route::group(['middleware' => ['auth:sanctum', 'locale']], function () { Route::get('dashboard/latest-torrent', [\App\Http\Controllers\DashboardController::class, 'latestTorrent']); Route::resource('settings', \App\Http\Controllers\SettingController::class); + Route::resource('medals', \App\Http\Controllers\MedalController::class); + Route::resource('user-medals', \App\Http\Controllers\UserMedalController::class); }); });