Skip to content

Commit 47977a0

Browse files
committed
Merge branch 'master' into beta
* master: Update POT files using the production database MBS-14179: Include the event being browsed in the response MBS-14188: Avoid extending `jQuery.fn` to unbreak some userscripts MBS-14137: Alert user when deleting work with relationships LoadReplicationChanges: Retry fetching packets on server errors Cleanup hourly JSON dumps/sitemaps $TEMP_DIR admin/RunIncrementalJSONDump: chmod 755 $TEMP_DIR Allow running ProcessSubscriptions for weekly only
2 parents d322882 + 66ea054 commit 47977a0

File tree

13 files changed

+241
-135
lines changed

13 files changed

+241
-135
lines changed

admin/RunIncrementalJSONDump

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ source admin/config.sh
2323
. ./admin/functions.sh
2424
make_temp_dir
2525

26+
# We use "$TEMP_DIR" directly as an rsync source below, which means its
27+
# permissions are transferred onto the remote directory as well. This sets
28+
# something more permissive than the default 0700, which allows the uwsgi
29+
# processes serving the incremental JSON dumps to be able to read them.
30+
chmod 755 "$TEMP_DIR"
31+
2632
# Create a clean test database from which to dump foreign keys.
2733
export REPLICATION_TYPE=3 # RT_STANDALONE
2834
./script/create_test_db.sh TEST
@@ -40,7 +46,11 @@ echo Making incremental JSON dumps
4046
--foreign-keys-dump "$FK_DUMP" \
4147
|| exit $?
4248

43-
cleanup() { rm -f "$FK_DUMP"; }
49+
cleanup() {
50+
rm -f "$FK_DUMP"
51+
# We've clobbered the trap set by `make_temp_dir`. Reinstate it.
52+
rmdir "$TEMP_DIR"
53+
}
4454
trap cleanup EXIT
4555

4656
# Was a dump created?

admin/cron/hourly-sitemaps.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@ FK_DUMP="$TEMP_DIR"/foreign_keys
2424
--foreign-keys-dump "$FK_DUMP" \
2525
--ping
2626

27-
cleanup() { rm -f "$FK_DUMP"; }
27+
cleanup() {
28+
rm -f "$FK_DUMP"
29+
# We've clobbered the trap set by `make_temp_dir`. Reinstate it.
30+
rmdir "$TEMP_DIR"
31+
}
2832
trap cleanup EXIT
2933

3034
./bin/rsync-sitemaps

admin/replication/LoadReplicationChanges

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,12 @@ use DBDefs;
1111
use integer;
1212

1313
use Getopt::Long;
14-
use HTTP::Status qw( RC_OK RC_NOT_FOUND RC_NOT_MODIFIED );
14+
use HTTP::Status qw(
15+
RC_OK
16+
RC_NOT_FOUND
17+
RC_NOT_MODIFIED
18+
is_server_error
19+
);
1520
use String::ShellQuote qw( shell_quote );
1621

1722
use MusicBrainz::Server::Replication qw(
@@ -208,24 +213,30 @@ if ($dbmirror2) {
208213
my $url = "$baseuri/$file";
209214
my $localfile = "$tmpdir/$file";
210215

211-
my $resp = retrieve_remote_file($url, $localfile, $fVerifySig);
212-
# We only understand a limited set of responses:
213-
# OK, not found, and the rest.
214-
215-
if ($resp->code == RC_NOT_FOUND)
216-
{
217-
# TODO check for newer replication packets, in case the server has lost one?
218-
# die if so
219-
220-
# Otherwise exit ok
221-
print localtime() . " : Replication packet #$iNextReplicationSequence not available\n";
222-
exit 0;
223-
}
224-
225-
unless ($resp->code == RC_OK or $resp->code == RC_NOT_MODIFIED)
226-
{
227-
print $resp->as_string;
228-
die;
216+
my $packet_retrieval_attempts = 0;
217+
while (1) {
218+
my $resp = retrieve_remote_file($url, $localfile, $fVerifySig);
219+
my $code = $resp->code;
220+
if ($code == RC_OK || $code == RC_NOT_MODIFIED) {
221+
last;
222+
} elsif ($code == RC_NOT_FOUND) {
223+
# TODO check for newer replication packets, in case the server has lost one?
224+
# die if so
225+
226+
# Otherwise exit ok
227+
print localtime() . " : Replication packet #$iNextReplicationSequence not available\n";
228+
exit 0;
229+
} else {
230+
print localtime() . " : Error retrieving $url:\n";
231+
print $resp->as_string;
232+
# Retry up to 3 times on server errors.
233+
if (is_server_error($code) && (++$packet_retrieval_attempts) <= 3) {
234+
print localtime() . " : Retrying in 10 seconds...\n";
235+
sleep 10;
236+
next;
237+
}
238+
die;
239+
}
229240
}
230241

231242
# We successfully retrieved the replication packet.

lib/MusicBrainz/Script/SubscriptionEmails.pm

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ has 'dry_run' => (
3838
cmd_flag => 'dry-run',
3939
);
4040

41+
has 'daily' => (
42+
isa => 'Bool',
43+
is => 'ro',
44+
default => 1,
45+
);
46+
4147
has 'weekly' => (
4248
isa => 'Bool',
4349
is => 'ro',
@@ -91,11 +97,17 @@ sub run {
9197
my $collator = get_collator('root');
9298
# plain UCA without language-specific tailoring
9399

100+
# We include "never" when processing daily subscriptions only to call
101+
# `update_subscriptions` on those editors.
102+
my @email_periods;
103+
push @email_periods, 'daily', 'never' if $self->daily;
104+
push @email_periods, 'weekly' if $self->weekly;
105+
94106
my $max = $self->c->model('Edit')->get_max_id;
95107
my $seen = 0;
96108
my $count;
97109
do {
98-
my @editors = $self->c->model('Editor')->editors_with_subscriptions($seen, $BATCH_SIZE);
110+
my @editors = $self->c->model('Editor')->editors_with_subscriptions(\@email_periods, $seen, $BATCH_SIZE);
99111
$count = @editors;
100112
printf "Starting batch with %d editors\n\n", $count if $self->verbose;
101113

@@ -105,8 +117,6 @@ sub run {
105117
printf "Processing subscriptions for '%s' (%s)\n", $editor->name, $period
106118
if $self->verbose;
107119

108-
next if $period eq 'weekly' && !$self->weekly;
109-
110120
unless ($period eq 'never') {
111121
my @subscriptions = $self->c->model('EditorSubscriptions')
112122
->get_all_subscriptions($editor->id);

lib/MusicBrainz/Server/Data/Editor.pm

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -710,7 +710,7 @@ sub load_for_collection {
710710
}
711711

712712
sub editors_with_subscriptions {
713-
my ($self, $after, $limit) = @_;
713+
my ($self, $email_periods, $after, $limit) = @_;
714714

715715
my @tables = (entities_with('subscriptions',
716716
take => sub { return 'editor_subscribe_' . (shift) }),
@@ -722,13 +722,14 @@ sub editors_with_subscriptions {
722722
LEFT JOIN editor_preference ep
723723
ON ep.editor = editor.id AND
724724
ep.name = 'subscriptions_email_period'
725-
WHERE editor.id > ?
725+
WHERE coalesce(ep.value, 'daily') = any(?)
726+
AND editor.id > ?
726727
AND editor.id IN ($ids)
727728
AND (editor.privs & $SPAMMER_FLAG) = 0
728729
ORDER BY editor.id ASC
729730
LIMIT ?";
730731

731-
$self->query_to_list($query, [$after, $limit], sub {
732+
$self->query_to_list($query, [$email_periods, $after, $limit], sub {
732733
my ($model, $row) = @_;
733734

734735
my $editor = $model->_new_from_row($row);

lib/MusicBrainz/Server/Data/Event.pm

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,15 @@ sub _order_by {
301301
return $order_by;
302302
}
303303

304+
=method find_by_events
305+
306+
Recursively find all events linked to the given event IDs via relationships,
307+
using the provided C<$limit> and C<$offset> parameters for pagination. Note
308+
that this also includes the events having the given C<$event_ids> in the
309+
results.
310+
311+
=cut
312+
304313
sub find_by_events {
305314
my ($self, $event_ids, $limit, $offset) = @_;
306315

@@ -331,6 +340,9 @@ sub find_by_events {
331340
)
332341
SELECT $columns FROM event
333342
WHERE id IN (
343+
-- The requested events (MBS-14179)
344+
SELECT unnest(\$1::INTEGER[]) event
345+
UNION ALL
334346
SELECT event FROM linked_entity0
335347
UNION ALL
336348
SELECT event FROM linked_entity1

po/mb_server.pot

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ msgstr ""
1010
"#-#-#-#-# mb_server.pot (PACKAGE VERSION) #-#-#-#-#\n"
1111
"Project-Id-Version: PACKAGE VERSION\n"
1212
"Report-Msgid-Bugs-To: \n"
13-
"POT-Creation-Date: 2025-10-27 17:21+0100\n"
13+
"POT-Creation-Date: 2025-11-13 12:11+0100\n"
1414
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1515
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1616
"Language-Team: LANGUAGE <[email protected]>\n"
@@ -15718,7 +15718,7 @@ msgstr ""
1571815718
#: ../root/static/scripts/relationship-editor/components/RelationshipPhraseGroup.js:160
1571915719
#: ../root/static/scripts/relationship-editor/components/RelationshipTargetTypeGroups.js:42
1572015720
#: ../root/static/scripts/release/components/RelationshipEditorBatchTools.js:50
15721-
#: ../root/static/scripts/release/components/TrackRelationshipEditor.js:376
15721+
#: ../root/static/scripts/release/components/TrackRelationshipEditor.js:403
1572215722
msgctxt "header"
1572315723
msgid "Add relationship"
1572415724
msgstr ""
@@ -16023,11 +16023,15 @@ msgstr ""
1602316023
msgid "Release group relationships"
1602416024
msgstr ""
1602516025

16026-
#: ../root/static/scripts/release/components/TrackRelationshipEditor.js:322
16026+
#: ../root/static/scripts/release/components/TrackRelationshipEditor.js:267
16027+
msgid "Are you sure you want to remove this work?"
16028+
msgstr ""
16029+
16030+
#: ../root/static/scripts/release/components/TrackRelationshipEditor.js:349
1602716031
msgid "Error loading work relationships: {error}"
1602816032
msgstr ""
1602916033

16030-
#: ../root/static/scripts/release/components/TrackRelationshipEditor.js:396
16034+
#: ../root/static/scripts/release/components/TrackRelationshipEditor.js:423
1603116035
msgid "Add related work"
1603216036
msgstr ""
1603316037

root/static/scripts/edit/MB/Control/ArtistEdit.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ export default function ArtistEdit() {
2323
* some of the labels below (like ended) might have other child nodes
2424
* this method supports replacing text without removing child nodes
2525
*/
26-
jQuery.fn.replaceText = function (newText) {
26+
function replaceText(newText) {
2727
return this.contents().filter(function () {
2828
return (this.nodeType === Node.TEXT_NODE &&
2929
this.nodeValue.trim() !== '');
3030
}).replaceWith(newText);
31-
};
31+
}
3232

3333

3434
self.$name = $('#id-edit-artist\\.name');
@@ -42,14 +42,14 @@ export default function ArtistEdit() {
4242
self.old_gender = self.$gender.val();
4343

4444
self.changeDateText = function (begin, end, ended) {
45-
self.$begin.replaceText(begin);
46-
self.$end.replaceText(end);
47-
self.$ended.replaceText(ended);
45+
replaceText.call(self.$begin, begin);
46+
replaceText.call(self.$end, end);
47+
replaceText.call(self.$ended, ended);
4848
};
4949

5050
self.changeAreaText = function (begin, end) {
51-
self.$beginarea.replaceText(begin);
52-
self.$endarea.replaceText(end);
51+
replaceText.call(self.$beginarea, begin);
52+
replaceText.call(self.$endarea, end);
5353
};
5454

5555
/*

root/static/scripts/release/components/TrackRelationshipEditor.js

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import type {
3838
import {
3939
compareTargetTypeWithGroup,
4040
iterateRelationshipsInTargetTypeGroup,
41+
iterateRelationshipsInTargetTypeGroups,
4142
} from '../../relationship-editor/utility/findState.js';
4243

4344
import EditWorkDialog from './EditWorkDialog.js';
@@ -244,12 +245,38 @@ component _RelatedWorkRelationshipEditor(
244245
]);
245246

246247
const removeWork = React.useCallback(() => {
248+
if (isNewWork) {
249+
let hasRelationships = false;
250+
for (
251+
const relationship of
252+
iterateRelationshipsInTargetTypeGroups(relatedWork.targetTypeGroups)
253+
) {
254+
if (
255+
relationship.entity0.entityType === 'recording' &&
256+
relationship.entity0.id === track.recording.id &&
257+
relationship.entity1.entityType === 'work' &&
258+
relationship.entity1.id === relatedWork.work.id
259+
) {
260+
continue;
261+
}
262+
hasRelationships = true;
263+
break;
264+
}
265+
if (hasRelationships) {
266+
const confirmed = window.confirm(
267+
l('Are you sure you want to remove this work?'),
268+
);
269+
if (!confirmed) {
270+
return;
271+
}
272+
}
273+
}
247274
dispatch({
248275
recording: track.recording,
249276
type: 'remove-work',
250277
workState: relatedWork,
251278
});
252-
}, [dispatch, track.recording, relatedWork]);
279+
}, [dispatch, track.recording, relatedWork, isNewWork]);
253280

254281
const removeWorkButton = React.useMemo(() => (
255282
<button

0 commit comments

Comments
 (0)