Skip to content

Commit 3f2223a

Browse files
authored
Merge branch 'master' into feature/fix-spotlight-factory-missing-state
2 parents 00172f3 + cf10c93 commit 3f2223a

File tree

9 files changed

+61
-32
lines changed

9 files changed

+61
-32
lines changed

app/Libraries/Search/BeatmapsetQueryParser.php

+3-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ public static function parse(?string $query): array
1515
$options = [];
1616

1717
// reference: https://github.com/ppy/osu/blob/f6baf49ad6b42c662a729ad05e18bd99bc48b4c7/osu.Game/Screens/Select/FilterQueryParser.cs
18-
$keywords = preg_replace_callback('#\b(?<key>\w+)(?<op>(:|=|(>|<)(:|=)?))(?<value>(".*")|(\S*))#i', function ($m) use (&$options) {
18+
// adjusted for multiple quoted options (with side effect of inner quotes must be escaped)
19+
$keywords = preg_replace_callback('#\b(?<key>\w+)(?<op>(:|=|(>|<)(:|=)?))(?<value>("{1,2})(?:\\\"|.)*?\7|\S*)#i', function ($m) use (&$options) {
1920
$key = strtolower($m['key']);
2021
$op = str_replace(':', '=', $m['op']);
2122
switch ($key) {
@@ -240,7 +241,7 @@ private static function makeIntRangeOption($operator, $value)
240241
private static function makeTextOption(string $operator, string $value): ?string
241242
{
242243
return $operator === '='
243-
? presence(preg_replace('/^"(.*)"$/', '$1', $value))
244+
? presence(strtr(preg_replace('/^"(.*)"$/', '$1', $value), ['\\"' => '"']))
244245
: null;
245246
}
246247

composer.lock

+10-10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

resources/js/beatmapsets-show/header.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { observer } from 'mobx-react';
1414
import core from 'osu-core-singleton';
1515
import * as React from 'react';
1616
import { hasGuestOwners } from 'utils/beatmap-helper';
17-
import { downloadLimited, getArtist, getTitle, toggleFavourite } from 'utils/beatmapset-helper';
17+
import { downloadLimited, getArtist, getTitle, makeSearchQueryOption, toggleFavourite } from 'utils/beatmapset-helper';
1818
import { classWithModifiers } from 'utils/css';
1919
import { formatNumber } from 'utils/html';
2020
import { trans } from 'utils/lang';
@@ -146,7 +146,7 @@ export default class Header extends React.Component<Props> {
146146
<span className='beatmapset-header__details-text beatmapset-header__details-text--title'>
147147
<a
148148
className='beatmapset-header__details-text-link'
149-
href={route('beatmapsets.index', { q: `title=""${getTitle(this.controller.beatmapset)}""` })}
149+
href={route('beatmapsets.index', { q: makeSearchQueryOption('title', getTitle(this.controller.beatmapset)) })}
150150
>
151151
{getTitle(this.controller.beatmapset)}
152152
</a>
@@ -163,7 +163,7 @@ export default class Header extends React.Component<Props> {
163163
<span className='beatmapset-header__details-text beatmapset-header__details-text--artist'>
164164
<a
165165
className='beatmapset-header__details-text-link'
166-
href={route('beatmapsets.index', { q: `artist=""${getArtist(this.controller.beatmapset)}""` })}
166+
href={route('beatmapsets.index', { q: makeSearchQueryOption('artist', getArtist(this.controller.beatmapset)) })}
167167
>
168168
{getArtist(this.controller.beatmapset)}
169169
</a>

resources/js/beatmapsets-show/info.tsx

+26-13
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { action, computed, makeObservable, observable, runInAction } from 'mobx'
1313
import { observer } from 'mobx-react';
1414
import * as React from 'react';
1515
import { onErrorWithClick } from 'utils/ajax';
16+
import { makeSearchQueryOption } from 'utils/beatmapset-helper';
1617
import { formatNumber } from 'utils/html';
1718
import { trans } from 'utils/lang';
1819
import { present } from 'utils/string';
@@ -65,15 +66,6 @@ export default class Info extends React.Component<Props> {
6566
return ret;
6667
}
6768

68-
private get tags() {
69-
const tags = this.controller.tags;
70-
71-
return [
72-
...tags.userTags.map((tag) => tag.name),
73-
...tags.mapperTags,
74-
];
75-
}
76-
7769
private get withEditDescription() {
7870
return this.controller.beatmapset.description.bbcode != null;
7971
}
@@ -163,7 +155,7 @@ export default class Info extends React.Component<Props> {
163155
</h3>
164156
<a
165157
className='beatmapset-info__link'
166-
href={route('beatmapsets.index', { q: `source=""${this.controller.beatmapset.source}""` })}
158+
href={route('beatmapsets.index', { q: makeSearchQueryOption('source', this.controller.beatmapset.source) })}
167159
>
168160
{this.controller.beatmapset.source}
169161
</a>
@@ -196,13 +188,34 @@ export default class Info extends React.Component<Props> {
196188
</div>
197189
</div>
198190

199-
{this.tags.length > 0 &&
191+
{this.controller.tags.userTags.length > 0 &&
192+
<div className='beatmapset-info__row beatmapset-info__row--value-overflow'>
193+
<h3 className='beatmapset-info__header'>
194+
{trans('beatmapsets.show.info.user_tags')}
195+
</h3>
196+
<div className='beatmapset-info__value-overflow'>
197+
{this.controller.tags.userTags.map((tag, i) => (
198+
<React.Fragment key={`${tag.name}-${i}`}>
199+
<a
200+
className='beatmapset-info__link'
201+
href={route('beatmapsets.index', { q: tag.name })}
202+
>
203+
{tag.name}
204+
</a>
205+
{' '}
206+
</React.Fragment>
207+
))}
208+
</div>
209+
</div>
210+
}
211+
212+
{this.controller.tags.mapperTags.length > 0 &&
200213
<div className='beatmapset-info__row beatmapset-info__row--value-overflow'>
201214
<h3 className='beatmapset-info__header'>
202-
{trans('beatmapsets.show.info.tags')}
215+
{trans('beatmapsets.show.info.mapper_tags')}
203216
</h3>
204217
<div className='beatmapset-info__value-overflow'>
205-
{this.tags.map((tag, i) => (
218+
{this.controller.tags.mapperTags.map((tag, i) => (
206219
<React.Fragment key={`${tag}-${i}`}>
207220
<a
208221
className='beatmapset-info__link'

resources/js/beatmapsets-show/metadata-editor.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ export default class MetadataEditor extends React.Component<Props> {
124124
{this.canEditTags &&
125125
<label className='simple-form__row'>
126126
<div className='simple-form__label'>
127-
{trans('beatmapsets.show.info.tags')}
127+
{trans('beatmapsets.show.info.mapper_tags')}
128128
</div>
129129

130130
<textarea

resources/js/cli/generate-localizations.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,14 @@ function getAllMesssages() {
3939
}
4040

4141
function generateTranslations() {
42-
spawnSync('php', [path.resolve(rootPath, 'artisan'), 'lang:js', '--json', messagesPath], { stdio: 'inherit' });
42+
spawnSync('php', [
43+
path.resolve(rootPath, 'artisan'),
44+
'lang:js',
45+
'--json',
46+
messagesPath,
47+
'--source',
48+
path.resolve(rootPath, 'resources/lang'),
49+
], { stdio: 'inherit' });
4350
}
4451

4552
function writeTranslations(languages) {

resources/js/utils/beatmapset-helper.ts

+4
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ export function getTitle(beatmapset: BeatmapsetJson) {
3434
return beatmapset.title;
3535
}
3636

37+
export function makeSearchQueryOption(key: string, value: string) {
38+
return `${key}=""${value.replace(/"/g, '\\"')}""`;
39+
}
40+
3741
export function showVisual(beatmapset: BeatmapsetJson) {
3842
return !beatmapset.nsfw || core.userPreferences.get('beatmapset_show_nsfw');
3943
}

resources/lang/en/beatmapsets.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,9 @@
148148
'source' => 'Source',
149149
'storyboard' => 'This beatmap contains storyboard',
150150
'success-rate' => 'Success Rate',
151-
'tags' => 'Tags',
152151
'video' => 'This beatmap contains video',
152+
'user_tags' => 'User Tags',
153+
'mapper_tags' => 'Mapper Tags',
153154
],
154155

155156
'nsfw_warning' => [

tests/Libraries/Search/BeatmapsetQueryParserTest.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,13 @@ public static function queryDataProvider()
4545
['ranked>2018/05/01', ['keywords' => null, 'options' => ['ranked' => ['gte' => static::parseTime('2018-05-02')]]]],
4646
['ranked>="2020-07-21 12:30:30 +09:00"', ['keywords' => null, 'options' => ['ranked' => ['gte' => static::parseTime('2020-07-21 03:30:30')]]]],
4747
['ranked="2020-07-21 12:30:30 +09:00"', ['keywords' => null, 'options' => ['ranked' => ['gte' => static::parseTime('2020-07-21 03:30:30'), 'lt' => static::parseTime('2020-07-21 03:30:31')]]]],
48+
['ranked>="2020-07-21 12:30:30 +09:00" ranked<="2020-08-21 13:40:40 +09:00"', ['keywords' => null, 'options' => ['ranked' => ['gte' => static::parseTime('2020-07-21 03:30:30'), 'lt' => static::parseTime('2020-08-21 04:40:41')]]]],
4849
['ranked="invalid date format"', ['keywords' => 'ranked="invalid date format"', 'options' => []]],
4950
['tag=hello', ['keywords' => null, 'options' => ['tag' => ['hello']]]],
5051
['tag=hello tag=world', ['keywords' => null, 'options' => ['tag' => ['hello', 'world']]]],
5152
['tag="hello world"', ['keywords' => null, 'options' => ['tag' => ['hello world']]]],
53+
['tag="hello world" tag="foo bar"', ['keywords' => null, 'options' => ['tag' => ['hello world', 'foo bar']]]],
54+
['tag="hello world"aa tag="foo bar"', ['keywords' => 'aa', 'options' => ['tag' => ['hello world', 'foo bar']]]],
5255

5356
// multiple options
5457
['artist=hello creator:world', ['keywords' => null, 'options' => ['artist' => 'hello', 'creator' => 'world']]],
@@ -88,7 +91,7 @@ public static function queryDataProvider()
8891
['find me songs by artist=singer please', ['keywords' => 'find me songs by please', 'options' => ['artist' => 'singer']]],
8992
['really like artist="name with space" yes', ['keywords' => 'really like yes', 'options' => ['artist' => 'name with space']]],
9093
['weird artist=double"quote', ['keywords' => 'weird', 'options' => ['artist' => 'double"quote']]],
91-
['weird artist="nested "quote"" thing', ['keywords' => 'weird thing', 'options' => ['artist' => 'nested "quote"']]],
94+
['weird artist="nested \"quote\"" thing', ['keywords' => 'weird thing', 'options' => ['artist' => 'nested "quote"']]],
9295
['artist=><something', ['keywords' => null, 'options' => ['artist' => '><something']]],
9396
['unrecognised=keyword', ['keywords' => 'unrecognised=keyword', 'options' => []]],
9497
['cs=nope', ['keywords' => 'cs=nope', 'options' => []]],

0 commit comments

Comments
 (0)