Skip to content

Commit

Permalink
Merge branch 'master' into recent-ended-at
Browse files Browse the repository at this point in the history
  • Loading branch information
peppy authored Apr 11, 2024
2 parents 1695401 + a1e27dd commit 3706926
Show file tree
Hide file tree
Showing 347 changed files with 3,307 additions and 611 deletions.
1 change: 0 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,6 @@ CLIENT_CHECK_VERSION=false

# USER_MAX_SCORE_PINS=10
# USER_MAX_SCORE_PINS_SUPPORTER=50
# USER_HIDE_PINNED_SOLO_SCORES=true

# the content is in markdown format
# USER_PROFILE_SCORES_NOTICE=
Expand Down
2 changes: 1 addition & 1 deletion app/Exceptions/ImageProcessorServiceException.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@

class ImageProcessorServiceException extends Exception
{
// doesn't really contain anything
const INVALID_IMAGE = 1;
}
14 changes: 8 additions & 6 deletions app/Hashing/OsuHasher.php → app/Hashing/OsuBcryptHasher.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

use Illuminate\Contracts\Hashing\Hasher;

class OsuHasher implements Hasher
class OsuBcryptHasher implements Hasher
{
/**
* The number of rounds to hash, as 2^n.
Expand Down Expand Up @@ -37,12 +37,10 @@ public function info($hashedValue)
*/
public function make($value, array $options = [])
{
$cost = array_get($options, 'cost', $this->rounds);

// When we originally moved to bcrypt (quite a few years ago),
// we had to migrate everything without waiting for every user to
// change their passwords, hence the md5 still being there.
$hash = password_hash(md5($value), PASSWORD_BCRYPT, ['cost' => $cost]);
$hash = password_hash(md5($value), PASSWORD_BCRYPT, ['cost' => $this->cost($options)]);

// see static::check()
return str_replace('$2y$', '$2a$', $hash);
Expand Down Expand Up @@ -83,9 +81,13 @@ public function check($value, $hashedValue, array $options = [])
*/
public function needsRehash($hashedValue, array $options = [])
{
$cost = array_get($options, 'cost', $this->rounds);
$hashedValue = str_replace('$2a$', '$2y$', $hashedValue);

return password_needs_rehash($hashedValue, PASSWORD_BCRYPT, ['cost' => $cost]);
return password_needs_rehash($hashedValue, PASSWORD_BCRYPT, ['cost' => $this->cost($options)]);
}

protected function cost(array $options): int
{
return $options['rounds'] ?? $this->rounds;
}
}
16 changes: 0 additions & 16 deletions app/Hashing/OsuHashManager.php

This file was deleted.

6 changes: 5 additions & 1 deletion app/Http/Controllers/BeatmapDiscussionsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,11 @@ public function index()

public function mediaUrl()
{
$url = get_string(request('url'));
$url = presence(get_string(request('url')));

if (!isset($url)) {
return response('Missing url parameter', 422);
}

// Tell browser not to request url for a while.
return redirect(proxy_media($url))->header('Cache-Control', 'max-age=600');
Expand Down
67 changes: 30 additions & 37 deletions app/Http/Controllers/ScorePinsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
namespace App\Http\Controllers;

use App\Jobs\RenumberUserScorePins;
use App\Libraries\MorphMap;
use App\Models\Beatmap;
use App\Models\ScorePin;
use App\Models\Solo;
use Exception;
Expand All @@ -23,29 +21,31 @@ public function __construct()

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

return response()->noContent();
}

public function reorder()
{
$rawParams = request()->all();
$targetParams = $this->getScoreParams($rawParams);
$rawParams = \Request::all();
$targetId = get_int($rawParams['score_id'] ?? null);

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

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

$order1Item = isset($adjacentScores['order1']['score_id'])
? $pinsQuery->clone()->where($adjacentScores['order1'])->first()
$order1Item = isset($adjacentScoreIds['order1'])
? $pinsQuery->clone()->find($adjacentScoreIds['order1'])
: null;
$order3Item = $order1Item === null && isset($adjacentScores['order3']['score_id'])
? $pinsQuery->clone()->where($adjacentScores['order3'])->first()
$order3Item = $order1Item === null && isset($adjacentScoreIds['order3'])
? $pinsQuery->clone()->find($adjacentScoreIds['order3'])
: null;

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

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

$target->update(['display_order' => $order2]);
Expand All @@ -73,33 +73,36 @@ public function reorder()

public function store()
{
$params = $this->getScoreParams(request()->all());

abort_if(!ScorePin::isValidType($params['score_type']), 422, 'invalid score_type');

$score = MorphMap::getClass($params['score_type'])::find($params['score_id']);
$id = get_int(request('score_id'));
$score = Solo\Score::find($id);

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

$user = auth()->user();
$user = \Auth::user();

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

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

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

$soloScore = $score instanceof Solo\Score
? $score
: Solo\Score::firstWhere(['ruleset_id' => $rulesetId, 'legacy_score_id' => $score->getKey()]);

try {
(new ScorePin([
'display_order' => $currentMinDisplayOrder - 100,
'ruleset_id' => $rulesetId,
'new_score_id' => $soloScore?->getKey(),

/**
* TODO:
* 1. update score_id = new_score_id
* 2. remove duplicated score_id
* 3. use score_id as primary key (both model and database)
* 4. remove setting score_type below
* 5. remove new_score_id and score_type columns
*/
'score_id' => $score->getKey(),
'score_type' => $score->getMorphClass(),
]))->user()->associate($user)
->score()->associate($score)
->saveOrExplode();
Expand All @@ -109,19 +112,9 @@ public function store()
}
}

if ($score instanceof Solo\Score) {
$score->update(['preserve' => true]);
}
$score->update(['preserve' => true]);
}

return response()->noContent();
}

private function getScoreParams(array $form)
{
return get_params($form, null, [
'score_type:string',
'score_id:int',
], ['null_missing' => true]);
}
}
12 changes: 8 additions & 4 deletions app/Http/Controllers/ScoresController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

namespace App\Http\Controllers;

use App\Enums\Ruleset;
use App\Models\Score\Best\Model as ScoreBest;
use App\Models\Solo\Score as SoloScore;
use App\Transformers\ScoreTransformer;
Expand Down Expand Up @@ -90,10 +91,13 @@ public function download($rulesetOrSoloId, $id = null)

public function show($rulesetOrSoloId, $legacyId = null)
{
[$scoreClass, $id] = $legacyId === null
? [SoloScore::class, $rulesetOrSoloId]
: [ScoreBest::getClass($rulesetOrSoloId), $legacyId];
$score = $scoreClass::whereHas('beatmap.beatmapset')->visibleUsers()->findOrFail($id);
$scoreQuery = $legacyId === null
? SoloScore::whereKey($rulesetOrSoloId)
: SoloScore::where([
'ruleset_id' => Ruleset::tryFromName($rulesetOrSoloId) ?? abort(404, 'unknown ruleset name'),
'legacy_score_id' => $legacyId,
]);
$score = $scoreQuery->whereHas('beatmap.beatmapset')->visibleUsers()->firstOrFail();

$userIncludes = array_map(function ($include) {
return "user.{$include}";
Expand Down
10 changes: 5 additions & 5 deletions app/Http/Controllers/WikiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,16 +123,16 @@ public function image($path)
return response('Invalid file format', 422);
}

$image = Wiki\Image::lookupForController($path, Request::url(), Request::header('referer'));

request()->attributes->set('strip_cookies', true);
$image = (new Wiki\Image($path))->sync();

if (!$image->isVisible()) {
return response('Not found', 404);
}

return response($image->get()['content'], 200)
->header('Content-Type', $image->get()['type'])
$imageData = $image->get();

return response($imageData['content'], 200)
->header('Content-Type', $imageData['type'])
// 10 years max-age
->header('Cache-Control', 'max-age=315360000, public');
}
Expand Down
1 change: 0 additions & 1 deletion app/Http/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ class Kernel extends HttpKernel
Middleware\VerifyUserAlways::class,
],
'web' => [
Middleware\StripCookies::class,
Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
Expand Down
23 changes: 0 additions & 23 deletions app/Http/Middleware/StripCookies.php

This file was deleted.

4 changes: 2 additions & 2 deletions app/Jobs/RenumberUserScorePins.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class RenumberUserScorePins implements ShouldQueue
{
use InteractsWithQueue, Queueable;

public function __construct(private int $userId, private string $scoreType)
public function __construct(private int $userId, private int $rulesetId)
{
}

Expand All @@ -24,7 +24,7 @@ public function handle()
DB::transaction(function () {
$pins = ScorePin
::where([
'score_type' => $this->scoreType,
'ruleset_id' => $this->rulesetId,
'user_id' => $this->userId,
])->orderBy('display_order', 'asc')
->lockForUpdate()
Expand Down
22 changes: 14 additions & 8 deletions app/Libraries/ImageProcessorService.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

use App\Exceptions\ImageProcessorServiceException;
use App\Models\Beatmapset;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;

class ImageProcessorService
{
Expand Down Expand Up @@ -42,15 +44,19 @@ public function process($method, $src)
$src = preg_replace('/https?:\/\//', '', $src);
try {
$tmpFile = tmpfile();
$bytesWritten = fwrite($tmpFile, file_get_contents($this->endpoint."/{$method}/{$src}"));
} catch (\ErrorException $e) {
if (strpos($e->getMessage(), 'HTTP request failed!') !== false) {
throw new ImageProcessorServiceException('HTTP request failed!');
} elseif (strpos($e->getMessage(), 'Connection refused') !== false) {
throw new ImageProcessorServiceException('Connection refused.');
} else {
throw $e;
$bytesWritten = fwrite(
$tmpFile,
(new Client())->request('GET', "{$this->endpoint}/{$method}/{$src}")->getBody()->getContents(),
);
} catch (GuzzleException $e) {
if (str_contains($e->getMessage(), 'VipsJpeg: Premature end of input file')) {
throw new ImageProcessorServiceException(
'Invalid image file',
ImageProcessorServiceException::INVALID_IMAGE,
$e,
);
}
throw new ImageProcessorServiceException('HTTP request failed!', 0, $e);
}

if ($bytesWritten === false || $bytesWritten < 100) {
Expand Down
8 changes: 8 additions & 0 deletions app/Libraries/Search/ArtistTrackSearch.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,18 @@ public function getQuery()
$this->addQueryStringFilter($query);
$this->addSimpleFilters($query);
$this->addTextFilters($query);
$this->addExclusiveOnlyFilter($query);

return $query;
}

private function addExclusiveOnlyFilter(BoolQuery $query): void
{
if ($this->params->exclusiveOnly) {
$query->filter(['term' => ['exclusive' => true]]);
}
}

private function addQueryStringFilter($query): void
{
$value = $this->params->queryString;
Expand Down
1 change: 1 addition & 0 deletions app/Libraries/Search/ArtistTrackSearchParams.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class ArtistTrackSearchParams extends SearchParams
public ?string $album;
public ?string $artist;
public ?array $bpm;
public bool $exclusiveOnly = false;
public ?string $genre;
public bool $isDefaultSort = false;
public ?array $length;
Expand Down
Loading

0 comments on commit 3706926

Please sign in to comment.