Skip to content

Commit cae2493

Browse files
authored
Merge branch 'master' into hasher-cleanup
2 parents 6a9aed6 + 813cccb commit cae2493

File tree

187 files changed

+2444
-1267
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

187 files changed

+2444
-1267
lines changed

Diff for: .env.example

+13-11
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,6 @@ CLIENT_CHECK_VERSION=false
246246

247247
# USER_MAX_SCORE_PINS=10
248248
# USER_MAX_SCORE_PINS_SUPPORTER=50
249-
# USER_HIDE_PINNED_SOLO_SCORES=true
250249

251250
# the content is in markdown format
252251
# USER_PROFILE_SCORES_NOTICE=
@@ -265,7 +264,7 @@ CLIENT_CHECK_VERSION=false
265264
# NOTIFICATION_CLEANUP_MAX_DELETE=50000
266265

267266
# The open source bounty info page/form url
268-
#OS_BOUNTY_URL=http://example.com/bounty_form
267+
# OS_BOUNTY_URL=http://example.com/bounty_form
269268

270269
# OAUTH_MAX_USER_CLIENTS=1
271270

@@ -292,16 +291,16 @@ CLIENT_CHECK_VERSION=false
292291
# PAGINATION_MAX_COUNT=10000
293292

294293
## Limits for the allowed number of simultaneous beatmapset uploads (displayed on the support page: /home/support)
295-
#BEATMAPSET_UPLOAD_ALLOWED=4
296-
#BEATMAPSET_UPLOAD_BONUS_PER_RANKED=1
297-
#BEATMAPSET_UPLOAD_BONUS_PER_RANKED_MAX=2
298-
#BEATMAPSET_UPLOAD_ALLOWED_SUPPORTER=8
299-
#BEATMAPSET_UPLOAD_BONUS_PER_RANKED_SUPPORTER=1
300-
#BEATMAPSET_UPLOAD_BONUS_PER_RANKED_MAX_SUPPORTER=12
294+
# BEATMAPSET_UPLOAD_ALLOWED=4
295+
# BEATMAPSET_UPLOAD_BONUS_PER_RANKED=1
296+
# BEATMAPSET_UPLOAD_BONUS_PER_RANKED_MAX=2
297+
# BEATMAPSET_UPLOAD_ALLOWED_SUPPORTER=8
298+
# BEATMAPSET_UPLOAD_BONUS_PER_RANKED_SUPPORTER=1
299+
# BEATMAPSET_UPLOAD_BONUS_PER_RANKED_MAX_SUPPORTER=12
301300

302-
#RECAPTCHA_SECRET=
303-
#RECAPTCHA_SITEKEY=
304-
#RECAPTCHA_THRESHOLD=
301+
# RECAPTCHA_SECRET=
302+
# RECAPTCHA_SITEKEY=
303+
# RECAPTCHA_THRESHOLD=
305304

306305
# TWITCH_CLIENT_ID=
307306
# TWITCH_CLIENT_SECRET=
@@ -336,3 +335,6 @@ CLIENT_CHECK_VERSION=false
336335

337336
# USER_COUNTRY_CHANGE_MAX_MIXED_MONTHS=2
338337
# USER_COUNTRY_CHANGE_MIN_MONTHS=6
338+
339+
# USER_INACTIVE_DAYS_VERIFICATION=180
340+
# USER_INACTIVE_FORCE_PASSWORD_RESET=false

Diff for: app/Exceptions/ImageProcessorServiceException.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@
99

1010
class ImageProcessorServiceException extends Exception
1111
{
12-
// doesn't really contain anything
12+
const INVALID_IMAGE = 1;
1313
}

Diff for: app/Http/Controllers/BeatmapDiscussionsController.php

+5-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,11 @@ public function index()
120120

121121
public function mediaUrl()
122122
{
123-
$url = get_string(request('url'));
123+
$url = presence(get_string(request('url')));
124+
125+
if (!isset($url)) {
126+
return response('Missing url parameter', 422);
127+
}
124128

125129
// Tell browser not to request url for a while.
126130
return redirect(proxy_media($url))->header('Cache-Control', 'max-age=600');

Diff for: app/Http/Controllers/BeatmapsController.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ private static function beatmapScores(string $id, ?string $scoreTransformerType,
7575
'type' => $type,
7676
'user' => $currentUser,
7777
]);
78-
$scores = $esFetch->all()->loadMissing(['beatmap', 'user.country', 'user.userProfileCustomization']);
78+
$scores = $esFetch->all()->loadMissing(['beatmap', 'user.country']);
7979
$userScore = $esFetch->userBest();
8080
$scoreTransformer = new ScoreTransformer($scoreTransformerType);
8181

Diff for: app/Http/Controllers/Forum/TopicsController.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use App\Models\Forum\TopicCover;
1717
use App\Models\Forum\TopicPoll;
1818
use App\Models\Forum\TopicWatch;
19+
use App\Models\UserProfileCustomization;
1920
use App\Transformers\Forum\TopicCoverTransformer;
2021
use Auth;
2122
use DB;
@@ -427,6 +428,7 @@ public function show($id)
427428

428429
$pollSummary = PollOption::summary($topic, $currentUser);
429430

431+
$topic->incrementViewCount($currentUser, \Request::ip());
430432
$posts->last()->markRead($currentUser);
431433

432434
$coverModel = $topic->cover ?? new TopicCover();
@@ -625,7 +627,7 @@ private function getIndexParams($topic, $currentUser, $userCanModerate)
625627
$params['limit'] = clamp($params['limit'] ?? 20, 1, 50);
626628

627629
if ($userCanModerate) {
628-
$params['with_deleted'] = $params['with_deleted'] ?? $currentUser->profileCustomization()->forum_posts_show_deleted;
630+
$params['with_deleted'] ??= ($currentUser->userProfileCustomization ?? UserProfileCustomization::DEFAULTS)['forum_posts_show_deleted'];
629631
} else {
630632
$params['with_deleted'] = false;
631633
}

Diff for: app/Http/Controllers/RankingController.php

+1-7
Original file line numberDiff line numberDiff line change
@@ -197,10 +197,6 @@ public function index($mode, $type)
197197
if (isset($forceIndex)) {
198198
$stats->from(DB::raw("{$table} FORCE INDEX ($forceIndex)"));
199199
}
200-
201-
if (is_api_request()) {
202-
$stats->with(['user.userProfileCustomization']);
203-
}
204200
}
205201

206202
$maxResults = $this->maxResults($modeInt, $stats);
@@ -304,13 +300,11 @@ public function spotlight($mode)
304300
}
305301

306302
if (is_api_request()) {
307-
$scores = $scores->with(['user.userProfileCustomization'])->get();
308-
309303
return [
310304
// transformer can't do nested includes with params properly.
311305
// https://github.com/thephpleague/fractal/issues/239
312306
'beatmapsets' => json_collection($beatmapsets, 'Beatmapset', ['beatmaps']),
313-
'ranking' => json_collection($scores, 'UserStatistics', ['user', 'user.cover', 'user.country']),
307+
'ranking' => json_collection($scores->get(), 'UserStatistics', ['user', 'user.cover', 'user.country']),
314308
'spotlight' => json_item($spotlight, 'Spotlight', ["participant_count:mode({$mode})"]),
315309
];
316310
} else {

Diff for: app/Http/Controllers/ScorePinsController.php

+34-34
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
namespace App\Http\Controllers;
77

88
use App\Jobs\RenumberUserScorePins;
9-
use App\Libraries\MorphMap;
10-
use App\Models\Beatmap;
119
use App\Models\ScorePin;
1210
use App\Models\Solo;
1311
use Exception;
@@ -23,29 +21,31 @@ public function __construct()
2321

2422
public function destroy()
2523
{
26-
auth()->user()->scorePins()->where($this->getScoreParams(request()->all()))->delete();
24+
\Auth::user()->scorePins()->whereKey(get_int(request('score_id')))->delete();
2725

2826
return response()->noContent();
2927
}
3028

3129
public function reorder()
3230
{
33-
$rawParams = request()->all();
34-
$targetParams = $this->getScoreParams($rawParams);
31+
$rawParams = \Request::all();
32+
$targetId = get_int($rawParams['score_id'] ?? null);
3533

36-
$pinsQuery = auth()->user()->scorePins();
37-
$target = $pinsQuery->clone()->where($targetParams)->firstOrFail();
34+
$pinsQuery = \Auth::user()->scorePins();
35+
$target = $pinsQuery->clone()->findOrFail($targetId);
36+
$rulesetId = $target->ruleset_id;
37+
$pinsQuery->where('ruleset_id', $rulesetId);
3838

3939
$adjacentScores = [];
4040
foreach (['order1', 'order3'] as $position) {
41-
$adjacentScores[$position] = $this->getScoreParams(get_arr($rawParams[$position] ?? null) ?? []);
41+
$adjacentScoreIds[$position] = get_int($rawParams[$position]['score_id'] ?? null);
4242
}
4343

44-
$order1Item = isset($adjacentScores['order1']['score_id'])
45-
? $pinsQuery->clone()->where($adjacentScores['order1'])->first()
44+
$order1Item = isset($adjacentScoreIds['order1'])
45+
? $pinsQuery->clone()->find($adjacentScoreIds['order1'])
4646
: null;
47-
$order3Item = $order1Item === null && isset($adjacentScores['order3']['score_id'])
48-
? $pinsQuery->clone()->where($adjacentScores['order3'])->first()
47+
$order3Item = $order1Item === null && isset($adjacentScoreIds['order3'])
48+
? $pinsQuery->clone()->find($adjacentScoreIds['order3'])
4949
: null;
5050

5151
abort_if($order1Item === null && $order3Item === null, 422, 'no valid pinned score reference is specified');
@@ -63,7 +63,7 @@ public function reorder()
6363
$order2 = ($order1 + $order3) / 2;
6464

6565
if ($order3 - $order1 < 0.1) {
66-
dispatch(new RenumberUserScorePins($target->user_id, $target->score_type));
66+
dispatch(new RenumberUserScorePins($target->user_id, $target->ruleset_id));
6767
}
6868

6969
$target->update(['display_order' => $order2]);
@@ -73,27 +73,37 @@ public function reorder()
7373

7474
public function store()
7575
{
76-
$params = $this->getScoreParams(request()->all());
77-
78-
abort_if(!ScorePin::isValidType($params['score_type']), 422, 'invalid score_type');
79-
80-
$score = MorphMap::getClass($params['score_type'])::find($params['score_id']);
76+
$id = get_int(request('score_id'));
77+
$score = Solo\Score::find($id);
8178

8279
abort_if($score === null, 422, "specified score couldn't be found");
8380

84-
$user = auth()->user();
81+
$user = \Auth::user();
8582

86-
$pin = ScorePin::where(['user_id' => $user->getKey()])->whereMorphedTo('score', $score)->first();
83+
$pin = $user->scorePins()->find($id);
8784

8885
if ($pin === null) {
8986
priv_check('ScorePin', $score)->ensureCan();
9087

91-
$rulesetId = Beatmap::MODES[$score->getMode()];
88+
$rulesetId = $score->ruleset_id;
9289
$currentMinDisplayOrder = $user->scorePins()->where('ruleset_id', $rulesetId)->min('display_order') ?? 2500;
9390

9491
try {
95-
(new ScorePin(['display_order' => $currentMinDisplayOrder - 100, 'ruleset_id' => $rulesetId]))
96-
->user()->associate($user)
92+
(new ScorePin([
93+
'display_order' => $currentMinDisplayOrder - 100,
94+
'ruleset_id' => $rulesetId,
95+
96+
/**
97+
* TODO:
98+
* 1. update score_id = new_score_id
99+
* 2. remove duplicated score_id
100+
* 3. use score_id as primary key (both model and database)
101+
* 4. remove setting score_type below
102+
* 5. remove new_score_id and score_type columns
103+
*/
104+
'score_id' => $score->getKey(),
105+
'score_type' => $score->getMorphClass(),
106+
]))->user()->associate($user)
97107
->score()->associate($score)
98108
->saveOrExplode();
99109
} catch (Exception $ex) {
@@ -102,19 +112,9 @@ public function store()
102112
}
103113
}
104114

105-
if ($score instanceof Solo\Score) {
106-
$score->update(['preserve' => true]);
107-
}
115+
$score->update(['preserve' => true]);
108116
}
109117

110118
return response()->noContent();
111119
}
112-
113-
private function getScoreParams(array $form)
114-
{
115-
return get_params($form, null, [
116-
'score_type:string',
117-
'score_id:int',
118-
], ['null_missing' => true]);
119-
}
120120
}

Diff for: app/Http/Controllers/ScoresController.php

+34-20
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,16 @@
55

66
namespace App\Http\Controllers;
77

8+
use App\Enums\Ruleset;
89
use App\Models\Score\Best\Model as ScoreBest;
910
use App\Models\Solo\Score as SoloScore;
10-
use App\Models\UserCountryHistory;
1111
use App\Transformers\ScoreTransformer;
1212
use App\Transformers\UserCompactTransformer;
13-
use Carbon\CarbonImmutable;
1413

1514
class ScoresController extends Controller
1615
{
16+
const REPLAY_DOWNLOAD_COUNT_INTERVAL = 86400; // 1 day
17+
1718
public function __construct()
1819
{
1920
parent::__construct();
@@ -52,20 +53,30 @@ public function download($rulesetOrSoloId, $id = null)
5253
abort(404);
5354
}
5455

55-
if (\Auth::user()->getKey() !== $score->user_id) {
56-
$score->user->statistics($score->getMode(), true)->increment('replay_popularity');
57-
58-
$month = CarbonImmutable::now();
59-
$currentMonth = UserCountryHistory::formatDate($month);
60-
61-
$score->user->replaysWatchedCounts()
62-
->firstOrCreate(['year_month' => $currentMonth], ['count' => 0])
63-
->incrementInstance('count');
64-
65-
if ($score instanceof ScoreBest) {
66-
$score->replayViewCount()
67-
->firstOrCreate([], ['play_count' => 0])
68-
->incrementInstance('play_count');
56+
$currentUser = \Auth::user();
57+
if (
58+
!$currentUser->isRestricted()
59+
&& $currentUser->getKey() !== $score->user_id
60+
&& ($currentUser->token()?->client->password_client ?? false)
61+
) {
62+
$countLock = \Cache::lock(
63+
"view:score_replay:{$score->getKey()}:{$currentUser->getKey()}",
64+
static::REPLAY_DOWNLOAD_COUNT_INTERVAL,
65+
);
66+
67+
if ($countLock->get()) {
68+
$score->user->statistics($score->getMode(), true)->increment('replay_popularity');
69+
70+
$currentMonth = format_month_column(new \DateTime());
71+
$score->user->replaysWatchedCounts()
72+
->firstOrCreate(['year_month' => $currentMonth], ['count' => 0])
73+
->incrementInstance('count');
74+
75+
if ($score instanceof ScoreBest) {
76+
$score->replayViewCount()
77+
->firstOrCreate([], ['play_count' => 0])
78+
->incrementInstance('play_count');
79+
}
6980
}
7081
}
7182

@@ -80,10 +91,13 @@ public function download($rulesetOrSoloId, $id = null)
8091

8192
public function show($rulesetOrSoloId, $legacyId = null)
8293
{
83-
[$scoreClass, $id] = $legacyId === null
84-
? [SoloScore::class, $rulesetOrSoloId]
85-
: [ScoreBest::getClass($rulesetOrSoloId), $legacyId];
86-
$score = $scoreClass::whereHas('beatmap.beatmapset')->visibleUsers()->findOrFail($id);
94+
$scoreQuery = $legacyId === null
95+
? SoloScore::whereKey($rulesetOrSoloId)
96+
: SoloScore::where([
97+
'ruleset_id' => Ruleset::tryFromName($rulesetOrSoloId) ?? abort(404, 'unknown ruleset name'),
98+
'legacy_score_id' => $legacyId,
99+
]);
100+
$score = $scoreQuery->whereHas('beatmap.beatmapset')->visibleUsers()->firstOrFail();
87101

88102
$userIncludes = array_map(function ($include) {
89103
return "user.{$include}";

Diff for: app/Http/Controllers/SessionsController.php

+2
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ public function store()
7777
$forceReactivation = new ForceReactivation($user, $request);
7878

7979
if ($forceReactivation->isRequired()) {
80+
DatadogLoginAttempt::log('password_reset');
8081
$forceReactivation->run();
8182

8283
\Session::flash('password_reset_start', [
@@ -87,6 +88,7 @@ public function store()
8788
return ujs_redirect(route('password-reset'));
8889
}
8990

91+
DatadogLoginAttempt::log(null);
9092
$this->login($user, $remember);
9193

9294
return [

0 commit comments

Comments
 (0)