Skip to content

Commit

Permalink
add option to filter by university groups: HSG, Institution, Guest
Browse files Browse the repository at this point in the history
  • Loading branch information
winprn committed Oct 18, 2023
1 parent 10925b5 commit afe95eb
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 14 deletions.
2 changes: 1 addition & 1 deletion judge/jinja2/reference.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ def link_user(user):
else:
display_badge_img = ''

return mark_safe(f'<span class="{profile.css_class}">'
return mark_safe(f'<span data-user-group="{ profile.group }" class="{profile.css_class}">'
f'<a href="{escape(reverse("user_page", args=[user.username]))}"'
f' style="display: inline-block;">'
f'{escape(profile.display_name)}</a>{display_badge_img}</span>')
Expand Down
9 changes: 6 additions & 3 deletions judge/management/commands/batch_add_icpc_team.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def generate_password():
return ''.join(secrets.choice(ALPHABET) for _ in range(8))


def add_user(username, teamname, password, org, internalid):
def add_user(username, teamname, password, org, org_group, internalid):
usr = User(username=username, is_active=True)
usr.set_password(password)
usr.save()
Expand All @@ -28,6 +28,7 @@ def add_user(username, teamname, password, org, internalid):
profile.language = Language.objects.get(key=settings.DEFAULT_USER_LANGUAGE)
profile.site_theme = 'light'
profile.notes = internalid # save the internal id for later use.
profile.group = org_group
profile.save()
profile.organizations.set([org])

Expand Down Expand Up @@ -68,7 +69,7 @@ def handle(self, *args, **options):
prefix = options['prefix']

reader = csv.DictReader(fin)
writer = csv.DictWriter(fout, fieldnames=['username', 'teamname', 'password'])
writer = csv.DictWriter(fout, fieldnames=['username', 'teamname', 'password', 'group'])
writer.writeheader()

for cnt, row in enumerate(reader, start=1):
Expand All @@ -77,13 +78,15 @@ def handle(self, *args, **options):
org = get_org(row['instName'])
password = generate_password()
internalid = row['id']
org_group = row['group']

add_user(username, teamname, password, org, internalid)
add_user(username, teamname, password, org, org_group, internalid)

writer.writerow({
'username': username,
'teamname': teamname,
'password': password,
'group': org_group
})

fin.close()
Expand Down
29 changes: 29 additions & 0 deletions judge/migrations/0199_auto_20231018_0702.py

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions judge/models/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@ class Profile(models.Model):
data_last_downloaded = models.DateTimeField(verbose_name=_('last data download time'), null=True, blank=True)
username_display_override = models.CharField(max_length=100, blank=True, verbose_name=_('display name override'),
help_text=_('Name displayed in place of username.'))
# For ICPC only
group = models.TextField(verbose_name=_('uni group'), null=True, blank=True)

@cached_property
def organization(self):
Expand Down
3 changes: 2 additions & 1 deletion judge/views/contests.py
Original file line number Diff line number Diff line change
Expand Up @@ -838,7 +838,7 @@ def get_context_data(self, **kwargs):

ContestRankingProfile = namedtuple(
'ContestRankingProfile',
'id user css_class username points cumtime tiebreaker organization participation '
'id user css_class username points cumtime tiebreaker organization participation group '
'participation_rating problem_cells result_cell virtual display_name',
)

Expand Down Expand Up @@ -870,6 +870,7 @@ def display_user_problem(contest_problem):
participation=participation,
virtual=participation.virtual,
display_name=user.display_name,
group=user.group,
)


Expand Down
2 changes: 1 addition & 1 deletion resources/contest.scss
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ form.contest-join-pseudotab {
}

#org-dropdown-check-list {
display: inline-block;
display: flex;
}

#org-check-list-wrapper {
Expand Down
10 changes: 10 additions & 0 deletions templates/contest/media-icpc-css.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,14 @@
font-size: 1.25em;
padding-bottom: -0.75em;
}

tr.top-team span.rating::after {
content: attr(data-user-group);
font-size: 0.75em;
padding: 0.25em;
margin-left: 0.5em;
background-color: #FFC008;
border-radius: 2px;
color: black;
}
</style>
98 changes: 91 additions & 7 deletions templates/contest/ranking.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@
.filter-checklist-button {
float: right;
}

.select-container {
display: flex;
gap: 2em;
}
</style>
{% endblock %}

Expand Down Expand Up @@ -81,17 +86,18 @@
window.enableAdminOperations();
window.loadOrgLogo();
window.applyFavoriteUsers();
window.applyTag();
}).always(function () {
ranking_outdated = false;
setTimeout(update_ranking, 10000);
// setTimeout(update_ranking, 10000);
});
}
$(window).on('dmoj:window-visible', function () {
if (ranking_outdated) {
update_ranking();
}
});
setTimeout(update_ranking, 10000);
// setTimeout(update_ranking, 10000);
});
</script>
{% endif %}
Expand Down Expand Up @@ -225,6 +231,48 @@
});
});

$(function() {
$('#tag-check-list').select2({
theme: '{{ DMOJ_SELECT2_THEME }}',
multiple: true,
closeOnSelect: false,
placeholder: '{{ _('Filter by group') }}',
});

const selection = $('#tag-check-list').data().select2.selection;
const results = $('#tag-check-list').data().select2.results;

$('#tag-check-list').on('select2:selecting', function(e) {
let id = e.params.args.data.id;
let val = $(e.target).val().concat([id]);
$(e.target).val(val).trigger('change');

if (selection.$search.val() != '') {
selection.$search.val('');
selection.trigger('query', {});
} else {
results.setClasses();
}

return false;
});

$('#tag-check-list').on('select2:unselecting', function(e) {
const id = e.params.args.data.id;
const val = $(e.target).val().filter(function(v) { return v != id; });
$(e.target).val(val).trigger('change');

if (selection.$search.val() != '') {
selection.$search.val('');
selection.trigger('query', {});
} else {
results.setClasses();
}

return false;
});
})

if (localStorage.getItem(`filter-cleared-${contest_key}`) === null) {
localStorage.setItem(`filter-cleared-${contest_key}`, 'true');
}
Expand All @@ -233,16 +281,23 @@
localStorage.setItem(`filter-selected-orgs-${contest_key}`, []);
}

if (localStorage.getItem(`filter-selected-group-${contest_key}`) === null) {
localStorage.setItem(`filter-selected-group-${contest_key}`, "");
}

$('#apply-organization-filter').click(function () {
$('#org-check-list-wrapper').hide();

let selected_orgs = $('#org-check-list').val().map(x => x.trim());
let selected_group = $('#tag-check-list').val().map(x => x.trim());
localStorage.setItem(`filter-selected-orgs-${contest_key}`, selected_orgs);
localStorage.setItem(`filter-selected-group-${contest_key}`, selected_group);
window.applyRankingFilter();
});

$('#clear-organization-filter').click(function () {
$('#org-check-list').val(null).trigger('change');
$('#tag-check-list').val(null).trigger('change');
$('#apply-organization-filter').click();
});

Expand All @@ -256,14 +311,18 @@
return;
}

if ($('#select2-org-check-list-results').has(e.target).length !== 0) {
if ($('#select2-org-check-list-results').has(e.target).length !== 0 || $('#select2-tag-check-list-results').has(e.target).length !== 0) {
return;
}

if ($(e.target).attr('id') && $(e.target).attr('id').startsWith('select2-org-check-list-result')) {
return;
}

if ($(e.target).attr('id') && $(e.target).attr('id').startsWith('select2-tag-check-list-result')) {
return;
}

// check if the clicked area is the checklist or not
if ($('#org-dropdown-check-list').has(e.target).length === 0) {
$('#apply-organization-filter').click();
Expand Down Expand Up @@ -324,8 +383,9 @@
let counter = 0;
let previous_abs_rank = -1;
let selected_orgs = localStorage.getItem(`filter-selected-orgs-${contest_key}`);
let selected_group = localStorage.getItem(`filter-selected-group-${contest_key}`);

if (!selected_orgs.length) {
if (!selected_orgs.length && !selected_group.length) {
window.clearRankingFilter();
return;
}
Expand All @@ -336,7 +396,7 @@
let org_anchor = row.find("div > div > .personal-info > .organization > a")[0];
let org = org_anchor ? org_anchor.text : 'Other';

if (!selected_orgs.includes(org.trim())) {
if (!selected_orgs.includes(org.trim()) && !selected_group.includes(row.data('user-group'))) {
row.hide();
return;
}
Expand Down Expand Up @@ -454,6 +514,27 @@
})
}
window.loadOrgLogo();

window.applyTag = function () {
const groups = [];
$('#ranking-table > tbody > tr[id]').each(function () {
let row = $(this);

if (groups.findIndex(x => x == row.data('user-group')) == -1) {
row.addClass('top-team');
groups.push(row.data('user-group'));
}
});

let tag_options = $('#tag-check-list');
tag_options.empty();
groups.forEach(function (group) {
tag_options.append(
`<option value="${group}">${group}</option>`
);
});
}
window.applyTag();
});

{% if tab == 'ranking' %}
Expand Down Expand Up @@ -556,11 +637,14 @@
</button>

<div id="org-check-list-wrapper">
<div>
<div style="margin-bottom: 30px;">
<button id="apply-organization-filter" class="inline-button filter-checklist-button">{{ _('Apply') }}</button>
<button id="clear-organization-filter" class="inline-button filter-checklist-button">{{ _('Clear') }}</button>
</div>
<select id="org-check-list" name="orgs[]" multiple="multiple"></select>
<div style="display: flex; gap: 2em;">
<select id="org-check-list" name="orgs[]" multiple="multiple"></select>
<select id="tag-check-list" name="tags[]" multiple="multiple"></select>
</div>
</div>
</div>
{% endif %}
Expand Down
2 changes: 1 addition & 1 deletion templates/user/base-users-table.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<tbody>
{% for rank, user in users %}
<tr id="user-{{ user.user.username }}" {% block row_extra scoped %}{% endblock %}>
<tr data-user-group="{{ user.group }}" id="user-{{ user.user.username }}" {% block row_extra scoped %}{% endblock %}>
<td>{{ rank }}</td>
{% block after_rank scoped %}{% endblock %}
<td class="user-name">
Expand Down

0 comments on commit afe95eb

Please sign in to comment.