Skip to content

Commit

Permalink
Show pseudonymized names (#1211)
Browse files Browse the repository at this point in the history
* Show pseudonymized names

---------

Co-authored-by: mikaelGusse <mikael.gustafsson@aalto.fi>
Co-authored-by: mikaelGusse <159019283+mikaelGusse@users.noreply.github.com>
  • Loading branch information
3 people committed Apr 4, 2024
1 parent 9e56353 commit 5290e8b
Show file tree
Hide file tree
Showing 16 changed files with 248 additions and 66 deletions.
18 changes: 16 additions & 2 deletions course/staff_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from lib.helpers import settings_text
from lib.viewbase import BaseFormView, BaseTemplateView, BaseRedirectMixin
from userprofile.models import UserProfile
from userprofile.pseudonymize import format_user
from .cache.students import CachedStudent
from .forms import EnrollStudentsForm, GroupEditForm
from .models import (
Expand All @@ -24,6 +25,13 @@
from .viewbase import CourseInstanceBaseView, CourseInstanceMixin


def format_group(group: StudentGroup, pseudonymized: bool):
if pseudonymized:
for member in group.members.all():
format_user(member.user, True, member)
return group


class ParticipantsView(CourseInstanceBaseView):
access_mode = ACCESS.ASSISTANT
template_name = "course/staff/participants.html"
Expand Down Expand Up @@ -63,6 +71,7 @@ def _get_students_with_tags(self) -> List[Dict[str, Any]]:
participants = ci.all_students.prefetch_tags(ci)
data = []
for participant in participants:
format_user(participant.user, self.pseudonymize, participant)
user_id = participant.user.id
user_tags = CachedStudent(ci, participant.user).data
user_tags_html = ' '.join(tags[slug].html_label for slug in user_tags['tag_slugs'] if slug in tags)
Expand Down Expand Up @@ -93,6 +102,8 @@ def get_common_objects(self) -> None:
models.Prefetch('members', UserProfile.objects.prefetch_tags(self.instance)),
)
)
for group in self.groups:
format_group(group, self.pseudonymize)
self.note('groups')


Expand All @@ -105,13 +116,15 @@ class GroupsEditView(CourseInstanceMixin, BaseFormView):
def get_resource_objects(self):
super().get_resource_objects()
gid = self._get_kwarg(self.group_kw, default=None)
group = None
if gid:
self.group = get_object_or_404(StudentGroup,
group = get_object_or_404(StudentGroup,
course_instance=self.instance,
id=gid,
)
else:
self.group = StudentGroup(course_instance=self.instance)
group = StudentGroup(course_instance=self.instance)
self.group = group

def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
Expand Down Expand Up @@ -145,6 +158,7 @@ def get_resource_objects(self) -> None:
course_instance=self.instance,
id=self._get_kwarg(self.group_kw),
)
format_group(self.group, self.pseudonymize)
self.note('group')

def post(self, request, *args, **kwargs):
Expand Down
13 changes: 13 additions & 0 deletions course/templates/course/_course_menu.html
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,19 @@ <h4>{% translate "COURSE_STAFF" %}</h4>
{% translate "SUBMISSION_DEVIATIONS" %}
</a>
</li>

<li class="menu-pseudonymize">
<a href="{% url 'toggle-pseudonymization' %}">
{% if pseudonymize %}
<span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span>
{% translate "UNPSEUDONYMIZE" %}
{% else %}
<span class="glyphicon glyphicon-eye-close" aria-hidden="true"></span>
{% translate "PSEUDONYMIZE" %}
{% endif %}
</a>
</li>

{% endif %}

{% for group in course_menu.staff_link_groups %}
Expand Down
4 changes: 2 additions & 2 deletions course/viewbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,10 @@ def get_resource_objects(self):
self.url_without_language = remove_query_param_from_url(self.request.get_full_path(), 'hl')
self.query_language = None
self.user_language = None

self.pseudonymize = self.request.session.get('pseudonymize', False)
self.note(
"instance", "is_student", "is_assistant", "is_teacher", "is_course_staff",
"url_without_language", "query_language", "user_language"
"url_without_language", "query_language", "user_language", "pseudonymize"
)

# Try to find a language that is defined for this course instance
Expand Down
9 changes: 6 additions & 3 deletions deviations/viewbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from authorization.permissions import ACCESS
from exercise.models import BaseExercise
from userprofile.models import UserProfile
from userprofile.pseudonymize import format_user


class ListDeviationsView(CourseInstanceBaseView):
Expand All @@ -27,7 +28,7 @@ def get_common_objects(self) -> None:
all_deviations = self.deviation_model.objects.filter(
exercise__course_module__course_instance=self.instance
)
self.deviation_groups = get_deviation_groups(all_deviations)
self.deviation_groups = get_deviation_groups(all_deviations, self.pseudonymize)
self.note("deviation_groups")


Expand Down Expand Up @@ -120,7 +121,7 @@ def get_common_objects(self) -> None:
exercise__in=self.exercises,
submitter__in=self.submitters,
)
self.deviation_groups = get_deviation_groups(self.existing_deviations)
self.deviation_groups = get_deviation_groups(self.existing_deviations, self.pseudonymize)
self.note("session_data", "exercises", "submitters", "existing_deviations", "deviation_groups")

def form_valid(self, form: forms.BaseForm) -> HttpResponse:
Expand Down Expand Up @@ -228,6 +229,7 @@ def form_valid(self, form: forms.BaseForm) -> HttpResponse:
# pylint: disable-next=too-many-locals
def get_deviation_groups(
all_deviations: models.QuerySet[SubmissionRuleDeviation],
pseudonymize: bool = False,
) -> Iterable[Tuple[List[SubmissionRuleDeviation], bool, Optional[str]]]:
"""
Group the deviations by user and module.
Expand Down Expand Up @@ -281,7 +283,8 @@ def get_deviation_groups(
ordered_deviations,
lambda obj: (obj.submitter, obj.exercise.course_module),
)
for (_submitter, module), deviations_iter in deviation_groups:
for (submitter, module), deviations_iter in deviation_groups:
format_user(submitter.user, pseudonymize, submitter)
deviations = list(deviations_iter)
can_group = True
show_granter = True
Expand Down
27 changes: 23 additions & 4 deletions exercise/staff_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from lib.viewbase import BaseRedirectView, BaseFormView, BaseView
from notification.models import Notification
from userprofile.models import UserProfile
from userprofile.pseudonymize import format_user
from .models import BaseExercise, ExerciseTask, LearningObject, Submission
from .forms import (
SubmissionReviewForm,
Expand All @@ -48,6 +49,14 @@
logger = logging.getLogger('aplus.exercise')


def format_submission(submission: Submission, pseudonymized: bool):
if pseudonymized:
for submitter in submission.submitters.all():
pseudo = True
format_user(submitter.user, pseudo, submitter)
return submission


class ListSubmissionsView(ExerciseListBaseView):
access_mode = ACCESS.ASSISTANT
template_name = "exercise/staff/list_submissions.html"
Expand All @@ -66,6 +75,8 @@ def get_common_objects(self) -> None:
Prefetch('submitters', UserProfile.objects.prefetch_tags(self.instance)),
)
)
for submission in qs:
format_submission(submission, self.pseudonymize)
self.all = self.request.GET.get('all', None)
self.all_url = self.exercise.get_submission_list_url() + "?all=yes"
self.submissions = qs if self.all else qs[:self.default_limit]
Expand Down Expand Up @@ -115,6 +126,10 @@ def get_common_objects(self) -> None:
.prefetch_tags(self.instance)
.in_bulk()
)
if self.pseudonymize:
for profile in profiles.values():
pseudo = True
format_user(profile.user, pseudo, profile)
# Add UserProfile instances to the dicts in submitter_summaries, so we can
# use the 'profiles' template tag.
for submitter_summary in submitter_summaries:
Expand Down Expand Up @@ -160,7 +175,7 @@ class InspectSubmissionView(SubmissionBaseView, BaseFormView):
def get_common_objects(self) -> None:
super().get_common_objects()
self.files = list(self.submission.files.all())

self.pseudonymize = self.request.session.get('pseudonymize', False)
self.lowest_visible_index = self.index - 10
self.highest_visible_index = self.index + 10

Expand All @@ -171,6 +186,7 @@ def get_common_objects(self) -> None:
self.not_best = False
self.not_last = False
for submission in self.submissions:
format_submission(self.submission, self.pseudonymize)
if submission.id != self.submission.id:
if submission.force_exercise_points:
self.not_final = True
Expand Down Expand Up @@ -393,8 +409,9 @@ def get_common_objects(self):
super().get_common_objects()
self.tags = [USERTAG_INTERNAL, USERTAG_EXTERNAL]
self.tags.extend(self.instance.usertags.all())
self.pseudonymize = self.request.session.get("pseudonymize", False)
self.note(
'tags',
'tags', 'pseudonymize',
)


Expand All @@ -407,8 +424,9 @@ def get_common_objects(self):
self.tags = list(self.instance.usertags.all())
self.internal_user_label = settings_text('INTERNAL_USER_LABEL')
self.external_user_label = settings_text('EXTERNAL_USER_LABEL')
self.pseudonymize = self.request.session.get("pseudonymize", False)
self.note(
'tags', 'internal_user_label', 'external_user_label',
'tags', 'internal_user_label', 'external_user_label', 'pseudonymize',
)


Expand All @@ -424,10 +442,11 @@ def studentpoints(self) -> CachedPoints:

def get_resource_objects(self):
super().get_resource_objects()
self.student = get_object_or_404(
student = get_object_or_404(
User,
id=self.kwargs[self.user_kw],
)
self.student = format_user(student, self.pseudonymize, student.userprofile)
self.note('student')

def get_common_objects(self):
Expand Down
18 changes: 11 additions & 7 deletions exercise/templates/exercise/_submission_info.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,18 @@ <h4 class="panel-title">{% translate "SUBMISSION_INFO" %}</h4>
{% translate "SUBMITTERS" %}
</dt>
<dd>
{% if is_course_staff %}
{% if is_teacher %}
<script src="{% static 'django_colortag.js' %}"></script>
<script src="{% static 'add_tagging_dropdown.js' %}"></script>
{% endif %}
{% profiles submission.submitters.all instance is_teacher %}
{% if not pseudonymize %}
{% if is_course_staff %}
{% if is_teacher %}
<script src="{% static 'django_colortag.js' %}"></script>
<script src="{% static 'add_tagging_dropdown.js' %}"></script>
{% endif %}
{% profiles submission.submitters.all instance is_teacher %}
{% else %}
{{ submission.submitters.all|names }}
{% endif %}
{% else %}
{{ submission.submitters.all|names }}
{% translate "PSEUDONYMIZED_SUBMITTERS" %}
{% endif %}
</dd>
</dl>
Expand Down
10 changes: 7 additions & 3 deletions exercise/templates/exercise/staff/_assessment_panel.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@
<div class="assessment-bar-fill assessment-bar-text">
{% if submission.grader %}
<span class="glyphicon glyphicon-ok" aria-hidden="true"></span>
{% blocktranslate trimmed with user=submission.grader.user.get_full_name time=submission.grading_time %}
ASSESSED_BY -- {{ user }}, {{ time }}
{% endblocktranslate %}
{% if not pseudonymize %}
{% blocktranslate trimmed with user=submission.grader.user.get_full_name time=submission.grading_time %}
ASSESSED_BY -- {{ user }}, {{ time }}
{% endblocktranslate %}
{% else %}
{% translate 'ASSESSED_BY' %} -- {% translate 'SOMEBODY' %}, {{ submission.grading_time }}
{% endif %}
{% else %}
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
{% translate 'NOT_ASSESSED_MANUALLY' %}
Expand Down
69 changes: 39 additions & 30 deletions exercise/templates/exercise/staff/analytics.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@
{% endblock %}

{% block columns %}
{% if pseudonymize %}
<div class="alert alert-warning clearfix site-message">
{% translate "PSEUDONYMIZATION_ERROR_MSG" %}
</div>
{% endif %}

<div class="col-md-12 llama-client">

<div id="llama-unit-select" role="navigation" aria-label="{% translate 'MODULE_SELECTION' %}">
Expand Down Expand Up @@ -107,41 +113,44 @@
{% endblock %}

{% block scripts %}

{{ block.super }}
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="{% static 'js/d3Stream.min.js' %}"></script>
<script src="{% static 'js/llama.min.js' %}"></script>
<link rel="stylesheet" href="{% static 'css/d3Stream.min.css' %}" />
<link rel="stylesheet" href="{% static 'css/llama.min.css' %}" />
<script>
$(function () {
new LlamaClient({

apiUrl: function (filter, download) {
var url = '{% url "api:course-aggregatedata-list" version=2 course_id=instance.id %}';
var a = '?';
if (filter && filter != '#all') {
url += '?filter=' + filter.substr(1);
a = '&';
}
if (download) {
url += a + 'format=csv';
}
return url;
},

userUrl: function (uid) {
var url = '{% url "user-results" course_slug=course.url instance_slug=instance.url user_id=0 %}';
return url.substr(0, url.length - 1) + uid;
},

progressLabels: [
'{% translate "NOT_SUBMITTED" %}',
'{% translate "PROGRESS_LABEL_<90%_POINTS" %}',
'{% translate "PROGRESS_LABEL_>=90%_POINTS" %}'
],

{% if not pseudonymize %}
<script>
$(function () {
new LlamaClient({

apiUrl: function (filter, download) {
var url = '{% url "api:course-aggregatedata-list" version=2 course_id=instance.id %}';
var a = '?';
if (filter && filter != '#all') {
url += '?filter=' + filter.substr(1);
a = '&';
}
if (download) {
url += a + 'format=csv';
}
return url;
},

userUrl: function (uid) {
var url = '{% url "user-results" course_slug=course.url instance_slug=instance.url user_id=0 %}';
return url.substr(0, url.length - 1) + uid;
},

progressLabels: [
'{% translate "NOT_SUBMITTED" %}',
'{% translate "PROGRESS_LABEL_<90%_POINTS" %}',
'{% translate "PROGRESS_LABEL_>=90%_POINTS" %}'
],

});
});
});
</script>
</script>
{% endif %}
{% endblock %}
Loading

0 comments on commit 5290e8b

Please sign in to comment.