diff --git a/app/Helpers/RatingHelper.php b/app/Helpers/RatingHelper.php deleted file mode 100644 index ea4fd3064..000000000 --- a/app/Helpers/RatingHelper.php +++ /dev/null @@ -1,46 +0,0 @@ -get('sort'); - /** @var \Illuminate\Support\Collection|\App\Models\User[] $users */ - $users = QueryBuilder::for(User::class) - ->defaultSort('name') - ->allowedSorts($sort ?? 'name') - ->withCount([ - 'chapterMembers', - 'exerciseMembers' => fn($query) => $query->finished(), - ]) - ->get(); - $calculatedRating = $users->map(fn(User $user) => [ - 'user' => $user, - 'points' => PointsCalculator::calculate($user->chapter_members_count, $user->exercise_members_count), - ]) - ->when(empty($sort), function ($collection) { - return $collection->sortByDesc('points'); - }) - ->values() - ->keyBy(fn($ratingPosition, $index) => $index + 1) - ->take(100); - - return $calculatedRating; - } - - public static function getParameterFromSorting(string $column, ?string $state): array - { - return match ($state) { - null => ['sort' => $column], - $column => ['sort' => "-{$column}"], - default => [], - }; - } -} diff --git a/app/Helpers/helpers.php b/app/Helpers/helpers.php index 142c8f6bc..406925123 100644 --- a/app/Helpers/helpers.php +++ b/app/Helpers/helpers.php @@ -50,10 +50,3 @@ function getExerciseOriginLink(Exercise $exercise): ?string return ExerciseHelper::getExerciseOriginLink($exercise); } } - -if (!function_exists('getCalculatedRating')) { - function getCalculatedRating(): Collection - { - return RatingHelper::getCalculatedRating(); - } -} diff --git a/app/Http/Controllers/Chapter/ChapterMemberController.php b/app/Http/Controllers/Chapter/ChapterMemberController.php index d5b73945f..120df23b1 100644 --- a/app/Http/Controllers/Chapter/ChapterMemberController.php +++ b/app/Http/Controllers/Chapter/ChapterMemberController.php @@ -7,7 +7,7 @@ use App\Models\ChapterMember; use App\Models\User; use App\Services\ActivityService; -use Flash; +use DB; use Illuminate\Http\RedirectResponse; class ChapterMemberController extends Controller @@ -18,8 +18,8 @@ public function finish(Chapter $chapter, ActivityService $activityService): Redi $currentChapterMember = $this->getMember($user, $chapter); $currentChapterMember->finish(); $currentChapterMember->save(); + $user->increment('points'); - // TODO: add points for finishing flash()->info(__('layout.flash.success'))->success(); $activityService->logChapterMemberFinished($currentChapterMember); diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index 8028c3ebb..4092f1cdb 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -10,7 +10,6 @@ use App\Models\Exercise; use App\Models\ChapterMember; use App\Models\User; -use App\Services\PointsCalculator; use Illuminate\Support\Carbon; use Illuminate\View\View; use Request; @@ -67,7 +66,6 @@ private function getStatisticTable(string $filter): array return [ 'countChapterMember' => $countChapterMember, 'countCompletedExercise' => $countCompletedExercise, - 'countPoints' => PointsCalculator::calculate($countChapterMember, $countCompletedExercise), 'filterForQuery' => $filter, ]; } diff --git a/app/Http/Controllers/Rating/ProgressController.php b/app/Http/Controllers/Rating/ProgressController.php deleted file mode 100644 index f5194ee04..000000000 --- a/app/Http/Controllers/Rating/ProgressController.php +++ /dev/null @@ -1,28 +0,0 @@ -get('sort'); - $nextChaptersParameterFromSort = RatingHelper::getParameterFromSorting('chapter_members_count', $sortParams); - $nextExercisesParameterFromSort = RatingHelper::getParameterFromSorting('exercise_members_count', $sortParams); - $rating = getCalculatedRating(); - $exercisesCount = Exercise::count(); - return view('rating.progress', compact( - 'rating', - 'exercisesCount', - 'sortParams', - 'nextChaptersParameterFromSort', - 'nextExercisesParameterFromSort', - )); - } -} diff --git a/app/Http/Controllers/Rating/TopController.php b/app/Http/Controllers/Rating/TopController.php new file mode 100644 index 000000000..31e914632 --- /dev/null +++ b/app/Http/Controllers/Rating/TopController.php @@ -0,0 +1,17 @@ +calculate(); + + return view('rating.top', compact('rating')); + } +} diff --git a/app/Http/Controllers/Rating/UserController.php b/app/Http/Controllers/Rating/UserController.php deleted file mode 100644 index a65d6a09c..000000000 --- a/app/Http/Controllers/Rating/UserController.php +++ /dev/null @@ -1,16 +0,0 @@ -search(function (array $ratingPosition) use ($user) { - ['user' => $ratingUser] = $ratingPosition; - return $ratingUser->id === $user->id; - }); - - if ($userRatingPosition) { - ['points' => $points] = $rating->get($userRatingPosition); + $rating = $ratingCalculator->calculate(); + $userInRating = $rating->get($user->id); + if ($userInRating) { + $points = $userInRating->points; + $position = $userInRating->position; } else { $points = 0; - $userRatingPosition = 'N/A'; + $position = 'N/A'; } $user->load('chapterMembers', 'exerciseMembers'); $chart = ChartHelper::getChart($user->id); return view('user.show', compact( 'user', - 'userRatingPosition', + 'position', 'points', 'chart' )); diff --git a/app/Services/ExerciseService.php b/app/Services/ExerciseService.php index 7d3641de8..7449682c7 100644 --- a/app/Services/ExerciseService.php +++ b/app/Services/ExerciseService.php @@ -13,6 +13,8 @@ class ExerciseService { + private const POINTS_PER_EXERCISE = 3; + public function __construct(private SolutionChecker $checker, private ActivityService $activityService) { } @@ -46,6 +48,7 @@ public function check(User $user, Exercise $exercise, string $solutionCode): Che if ($checkResult->isSuccess() && $user->isRegistered()) { if ($exerciseMember->mayFinish()) { $exerciseMember->finish(); + $user->increment('points', self::POINTS_PER_EXERCISE); $exerciseMember->save(); $this->activityService->logCompletedExercise($user, $exercise); diff --git a/app/Services/PointsCalculator.php b/app/Services/PointsCalculator.php deleted file mode 100644 index f1f375635..000000000 --- a/app/Services/PointsCalculator.php +++ /dev/null @@ -1,11 +0,0 @@ -selectRaw('DENSE_RANK() OVER (ORDER BY points desc, created_at) AS position') + ->where('points', '>', 0) + ->limit(100) + ->get() + ->keyBy('id'); + return $ratings; + } +} diff --git a/database/migrations/2024_03_27_174229_add_points_to_user.php b/database/migrations/2024_03_27_174229_add_points_to_user.php new file mode 100644 index 000000000..e876147d6 --- /dev/null +++ b/database/migrations/2024_03_27_174229_add_points_to_user.php @@ -0,0 +1,32 @@ +addColumn('integer', 'points')->default(0); + }); + DB::statement("UPDATE users SET points = ((SELECT count(user_id) FROM exercise_members em WHERE em.user_id = users.id) * 3);"); + DB::statement("UPDATE users SET points = points + (SELECT count(user_id) FROM chapter_members em WHERE em.user_id = users.id);"); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('points'); + }); + } +}; diff --git a/resources/lang/en/rating.php b/resources/lang/en/rating.php index ee3aa6ea8..27731b865 100644 --- a/resources/lang/en/rating.php +++ b/resources/lang/en/rating.php @@ -9,10 +9,6 @@ 'title' => 'Top commenters', 'description' => 'The sicp.hexlet.ru top commenters ranking', ], - 'progress' => [ - 'title' => 'Top students', - 'description' => 'The sicp.hexlet.ru top students ranking', - ], 'positions' => 'Rank', 'user' => 'Username', 'number_of_points' => 'Points', diff --git a/resources/lang/ru/rating.php b/resources/lang/ru/rating.php index c01467ede..2250bb640 100644 --- a/resources/lang/ru/rating.php +++ b/resources/lang/ru/rating.php @@ -9,10 +9,6 @@ 'title' => 'Вклад в сообщество', 'description' => 'Рейтиг участников платформы sicp.hexlet.ru по вкладу в сообщество', ], - 'progress' => [ - 'title' => 'Прогресс', - 'description' => 'Рейтиг участников платформы sicp.hexlet.ru в соответсвии с прогрессом изучения материалов книги СИКП', - ], 'positions' => 'Позиция', 'user' => 'Пользователь', 'number_of_points' => 'Количество баллов', diff --git a/resources/views/home/index.blade.php b/resources/views/home/index.blade.php index 59ca31f12..d2362d1e2 100644 --- a/resources/views/home/index.blade.php +++ b/resources/views/home/index.blade.php @@ -47,10 +47,6 @@
-
-

{{ __('welcome.statistic.table.count_points') }}:

-

{{ $statisticTable['countPoints'] }}

-

{{ __('welcome.statistic.table.count_read_chapter') }}:

{{ $statisticTable['countChapterMember'] }}

diff --git a/resources/views/rating/menu.blade.php b/resources/views/rating/_menu.blade.php similarity index 69% rename from resources/views/rating/menu.blade.php rename to resources/views/rating/_menu.blade.php index f8bb928ca..29fec6d8f 100644 --- a/resources/views/rating/menu.blade.php +++ b/resources/views/rating/_menu.blade.php @@ -2,9 +2,6 @@ {{ __('rating.index.title') }} - - {{ __('rating.progress.title') }} - {{ __('rating.comments.title') }} diff --git a/resources/views/rating/comments.blade.php b/resources/views/rating/comments.blade.php index dba6150b1..44b0316e4 100644 --- a/resources/views/rating/comments.blade.php +++ b/resources/views/rating/comments.blade.php @@ -4,7 +4,7 @@ @endsection @section('content')
- @include('rating.menu') + @include('rating._menu')

{{ __('rating.comments.title') }}

diff --git a/resources/views/rating/progress.blade.php b/resources/views/rating/progress.blade.php deleted file mode 100644 index 0b38b825c..000000000 --- a/resources/views/rating/progress.blade.php +++ /dev/null @@ -1,54 +0,0 @@ -@extends('layouts.app') -@section('description') - {{ __('rating.progress.description') }} -@endsection -@section('content') -
- @include('rating.menu') -

{{ __('rating.progress.title') }}

-
- - - - - - - - - - @foreach ($rating as $position => - [ - 'user' => $user, - ]) - - - - - - - @endforeach - -
{{ __('rating.positions') }}{{ __('rating.user') }} - @include('components.sorting_widget', [ - 'sortParams' => $sortParams, - 'nameParams' => 'chapter_members_count', - 'name' => __('rating.chapter_members_from', ['count' => App\Models\Chapter::MARKABLE_COUNT]), - 'route' => route('progress_top.index', $nextChaptersParameterFromSort), - ]) - - @include('components.sorting_widget', [ - 'sortParams' => $sortParams, - 'nameParams' => 'exercise_members_count', - 'name' => __('rating.exercise_members_from', ['count' => $exercisesCount]), - 'route' => route('progress_top.index', $nextExercisesParameterFromSort), - ]) -
{{ $position }} - - Profile image - {{ $user->name }} - - {{ $user->chapter_members_count }}{{ $user->exercise_members_count }}
-
-
-@endsection diff --git a/resources/views/rating/index.blade.php b/resources/views/rating/top.blade.php similarity index 85% rename from resources/views/rating/index.blade.php rename to resources/views/rating/top.blade.php index c71d15f59..f99e91b7d 100644 --- a/resources/views/rating/index.blade.php +++ b/resources/views/rating/top.blade.php @@ -7,7 +7,7 @@ @endsection @section('content')
- @include('rating.menu') + @include('rating._menu')

{{ __('rating.index.title') }}

@@ -22,9 +22,9 @@ - @foreach ($rating as $position => ['user' => $user, 'points' => $points]) + @foreach ($rating as $user) - {{ $position }} + {{ $user->position }} name }} - {{ $points }} + {{ $user->points }} @endforeach diff --git a/resources/views/user/show.blade.php b/resources/views/user/show.blade.php index fb6fc07b7..7da5866a3 100644 --- a/resources/views/user/show.blade.php +++ b/resources/views/user/show.blade.php @@ -20,7 +20,7 @@

{{ $user->name }}

- {{ $userRatingPosition }} + {{ $position }} {{ __('user.show.statistics.rating') }} diff --git a/routes/web.php b/routes/web.php index f26753351..b920bc4f6 100644 --- a/routes/web.php +++ b/routes/web.php @@ -24,14 +24,12 @@ Route::resource('users', 'UserController')->only('show'); Route::namespace('User')->group(function (): void { - Route::resource('users.chapters', 'UserChapterController')->only('store', 'destroy'); Route::resource('users.solutions', 'SolutionController')->only('store', 'show', 'destroy'); Route::resource('users.comments', 'UserCommentController')->only('index'); }); Route::namespace('Rating')->prefix('ratings')->group(function (): void { - Route::resource('top', 'UserController')->only('index'); - Route::resource('progress_top', 'ProgressController')->only('index'); + Route::resource('top', 'TopController')->only('index'); Route::resource('comments_top', 'CommentController')->only('index'); }); diff --git a/tests/Feature/Http/Controllers/Rating/ProgressControllerTest.php b/tests/Feature/Http/Controllers/Rating/ProgressControllerTest.php deleted file mode 100644 index cf2bf6ef0..000000000 --- a/tests/Feature/Http/Controllers/Rating/ProgressControllerTest.php +++ /dev/null @@ -1,34 +0,0 @@ -count(10)->create(); - $users->chunk(2)->each(function (Collection $chunk, $i) { - $chunk->each(function (User $user) use ($i): void { - $chapters = Chapter::inRandomOrder()->limit($i)->get(); - $exercises = Exercise::inRandomOrder()->limit($i)->get(); - $user->chapters()->saveMany($chapters); - $user->exercises()->saveMany($exercises); - }); - }); - - $this->get(route('progress_top.index')) - ->assertOk(); - } - - public function testIndexWithEmptyRating(): void - { - $this->get(route('progress_top.index')) - ->assertOk(); - } -} diff --git a/tests/Feature/Http/Controllers/Rating/UserControllerTest.php b/tests/Feature/Http/Controllers/Rating/TopControllerTest.php similarity index 95% rename from tests/Feature/Http/Controllers/Rating/UserControllerTest.php rename to tests/Feature/Http/Controllers/Rating/TopControllerTest.php index ad86384aa..aa7d994ea 100644 --- a/tests/Feature/Http/Controllers/Rating/UserControllerTest.php +++ b/tests/Feature/Http/Controllers/Rating/TopControllerTest.php @@ -8,7 +8,7 @@ use Tests\TestCase; use Illuminate\Support\Collection; -class UserControllerTest extends TestCase +class TopControllerTest extends TestCase { public function testIndex(): void {