Skip to content

Commit 92c9f85

Browse files
Refactor reviewer queue policy handling of "skip" setting. Fixes ietf-tools#3038. Commit ready for merge.
- Legacy-Id: 18833
1 parent a55b008 commit 92c9f85

5 files changed

Lines changed: 985 additions & 336 deletions

File tree

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Generated by Django 2.2.17 on 2021-01-24 07:24
2+
3+
from django.db import migrations, models
4+
5+
6+
7+
def forward(apps, schema_editor):
8+
"""Forward migration
9+
10+
Attempts to reconcile and remove duplicate ReviewerSettings
11+
"""
12+
ReviewerSettings = apps.get_model('review', 'ReviewerSettings')
13+
HistoricalReviewerSettings = apps.get_model('review', 'HistoricalReviewerSettings')
14+
15+
def reconcile_duplicate_settings(duplicate_settings, histories):
16+
"""Helper to decide how to handle duplicate settings"""
17+
team = duplicate_settings[0].team
18+
person = duplicate_settings[0].person
19+
assert(all((s.person == person and s.team == team for s in duplicate_settings)))
20+
21+
print('\n>> Found duplicate settings for {}'.format(duplicate_settings[0]))
22+
# In the DB as of Dec 2020, the only duplicate settings sets were pairs where the
23+
# earlier PK had a change history and the latter PK did not. Based on this, assuming
24+
# a change history indicates that the settings are important. If only one has history,
25+
# use that one. If multiple have a history, throw an error.
26+
settings_with_history = [s for s in duplicate_settings if histories[s.pk].count() > 0]
27+
if len(settings_with_history) == 0:
28+
duplicate_settings.sort(key=lambda s: s.pk)
29+
keep = duplicate_settings[-1]
30+
reason = 'chosen by pk'
31+
elif len(settings_with_history) == 1:
32+
keep = settings_with_history[0]
33+
reason = 'chosen because has change history'
34+
else:
35+
# Don't try to guess what to do if multiple settings have change histories
36+
raise RuntimeError(
37+
'Multiple ReviewerSettings with change history for {}. Please resolve manually.'.format(
38+
settings_with_history[0]
39+
)
40+
)
41+
42+
print('>> Keeping pk={} ({})'.format(keep.pk, reason))
43+
for settings in duplicate_settings:
44+
if settings.pk != keep.pk:
45+
print('>> Deleting pk={}'.format(settings.pk))
46+
settings.delete()
47+
48+
# forward migration starts here
49+
if ReviewerSettings.objects.count() == 0:
50+
return # nothing to do
51+
52+
records = dict() # list of records, keyed by (person_id, team_id)
53+
for rs in ReviewerSettings.objects.all().order_by('pk'):
54+
key = (rs.person_id, rs.team_id)
55+
if key in records:
56+
records[key].append(rs)
57+
else:
58+
records[key] = [rs]
59+
60+
for duplicate_settings in records.values():
61+
if len(duplicate_settings) > 1:
62+
histories = dict()
63+
for ds in duplicate_settings:
64+
histories[ds.pk] = HistoricalReviewerSettings.objects.filter(
65+
id=ds.pk
66+
)
67+
reconcile_duplicate_settings(duplicate_settings, histories)
68+
69+
def reverse(apps, schema_editor):
70+
"""Reverse migration
71+
72+
Does nothing, but no harm in reverse migration.
73+
"""
74+
pass
75+
76+
77+
class Migration(migrations.Migration):
78+
79+
dependencies = [
80+
('review', '0026_repair_more_assignments'),
81+
]
82+
83+
operations = [
84+
migrations.RunPython(forward, reverse),
85+
migrations.AddConstraint(
86+
model_name='reviewersettings',
87+
constraint=models.UniqueConstraint(fields=('team', 'person'), name='unique_reviewer_settings_per_team_person'),
88+
),
89+
]

ietf/review/models.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ def __str__(self):
4545

4646
class Meta:
4747
verbose_name_plural = "reviewer settings"
48+
constraints = [models.UniqueConstraint(fields=['team', 'person'],
49+
name='unique_reviewer_settings_per_team_person')]
4850

4951
class ReviewSecretarySettings(models.Model):
5052
"""Keeps track of admin data associated with a secretary in a team."""

0 commit comments

Comments
 (0)