1<?php
2
3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0.
4// See the LICENCE file in the repository root for full licence text.
5
6namespace App\Http\Controllers;
7
8use App\Jobs\RenumberUserScorePins;
9use App\Models\ScorePin;
10use App\Models\Solo;
11use Exception;
12
13class ScorePinsController extends Controller
14{
15 public function __construct()
16 {
17 $this->middleware('auth');
18
19 parent::__construct();
20 }
21
22 public function destroy()
23 {
24 \Auth::user()->scorePins()->whereKey(get_int(request('score_id')))->delete();
25
26 return response()->noContent();
27 }
28
29 public function reorder()
30 {
31 $rawParams = \Request::all();
32 $targetId = get_int($rawParams['score_id'] ?? null);
33
34 $pinsQuery = \Auth::user()->scorePins();
35 $target = $pinsQuery->clone()->findOrFail($targetId);
36 $rulesetId = $target->ruleset_id;
37 $pinsQuery->where('ruleset_id', $rulesetId);
38
39 $adjacentScores = [];
40 foreach (['order1', 'order3'] as $position) {
41 $adjacentScoreIds[$position] = get_int($rawParams[$position]['score_id'] ?? null);
42 }
43
44 $order1Item = isset($adjacentScoreIds['order1'])
45 ? $pinsQuery->clone()->find($adjacentScoreIds['order1'])
46 : null;
47 $order3Item = $order1Item === null && isset($adjacentScoreIds['order3'])
48 ? $pinsQuery->clone()->find($adjacentScoreIds['order3'])
49 : null;
50
51 abort_if($order1Item === null && $order3Item === null, 422, 'no valid pinned score reference is specified');
52
53 if ($order1Item === null) {
54 $order3 = $order3Item->display_order;
55 $order1 = $pinsQuery->clone()->where('display_order', '<', $order3)->max('display_order')
56 ?? $order3 - 200;
57 } else {
58 $order1 = $order1Item->display_order;
59 $order3 = $pinsQuery->clone()->where('display_order', '>', $order1)->min('display_order')
60 ?? $order1 + 200;
61 }
62
63 $order2 = ($order1 + $order3) / 2;
64
65 if ($order3 - $order1 < 0.1) {
66 dispatch(new RenumberUserScorePins($target->user_id, $target->ruleset_id));
67 }
68
69 $target->update(['display_order' => $order2]);
70
71 return response()->noContent();
72 }
73
74 public function store()
75 {
76 $id = get_int(request('score_id'));
77 $score = Solo\Score::find($id);
78
79 abort_if($score === null, 422, "specified score couldn't be found");
80
81 $user = \Auth::user();
82
83 $pin = $user->scorePins()->find($id);
84
85 if ($pin === null) {
86 priv_check('ScorePin', $score)->ensureCan();
87
88 $rulesetId = $score->ruleset_id;
89 $currentMinDisplayOrder = $user->scorePins()->where('ruleset_id', $rulesetId)->min('display_order') ?? 2500;
90
91 try {
92 (new ScorePin([
93 'display_order' => $currentMinDisplayOrder - 100,
94 'ruleset_id' => $rulesetId,
95 ]))->user()->associate($user)
96 ->score()->associate($score)
97 ->saveOrExplode();
98 } catch (Exception $ex) {
99 if (!is_sql_unique_exception($ex)) {
100 throw $ex;
101 }
102 }
103
104 $score->update(['preserve' => true]);
105 }
106
107 return response()->noContent();
108 }
109}