Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Non-admin CRUD views for ParticipationTag and ParticipationRole #745

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions course/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ class participation_permission: # noqa
query_participation = "query_participation"
edit_participation = "edit_participation"
preapprove_participation = "preapprove_participation"
edit_participation_role = "edit_participation_role"
edit_participation_tag = "edit_participation_tag"

manage_instant_flow_requests = "manage_instant_flow_requests"

Expand Down Expand Up @@ -248,6 +250,12 @@ class participation_permission: # noqa
pgettext_lazy("Participation permission", "Edit participation")),
(participation_permission.preapprove_participation,
pgettext_lazy("Participation permission", "Preapprove participation")),
(participation_permission.edit_participation_role,
pgettext_lazy(
"Participation permission", "Edit participation role")),
(participation_permission.edit_participation_tag,
pgettext_lazy(
"Participation permission", "Edit participation tag")),

(participation_permission.manage_instant_flow_requests,
pgettext_lazy("Participation permission",
Expand Down
190 changes: 190 additions & 0 deletions course/enrollment.py
Original file line number Diff line number Diff line change
Expand Up @@ -1110,4 +1110,194 @@ def edit_participation(pctx, participation_id):

# }}}


# {{{ edit_participation_tag

class EditParticipationTagForm(StyledModelForm):
def __init__(self, add_new, *args, **kwargs):
# type: (bool, *Any, **Any) -> None
super(EditParticipationTagForm, self).__init__(*args, **kwargs)

if add_new:
self.helper.add_input(
Submit("submit", _("Add"), css_class="btn-success"))
else:
self.helper.add_input(
Submit("submit", _("Update"), css_class="btn-success"))
self.helper.add_input(
Submit("delete", _("Delete"), css_class="btn-danger"))

class Meta:
model = ParticipationTag
exclude = ("course",)


@course_view
def view_participation_tag_list(pctx):
if not pctx.has_permission(pperm.view_gradebook):
raise PermissionDenied(_("may not edit participation tags"))

participation_tags = list(ParticipationTag.objects.filter(course=pctx.course))

return render_course_page(pctx, "course/participation-tag-list.html", {
"participation_tags": participation_tags,
})


@course_view
def edit_participation_tag(pctx, ptag_id):
# type: (CoursePageContext, int) -> http.HttpResponse
if not pctx.has_permission(pperm.edit_participation_tag):
raise PermissionDenied()

request = pctx.request

num_ptag_id = int(ptag_id)

if num_ptag_id == -1:
ptag = ParticipationTag(course=pctx.course)
add_new = True
else:
ptag = get_object_or_404(ParticipationTag, id=num_ptag_id)
add_new = False

if ptag.course.id != pctx.course.id:
raise SuspiciousOperation(
"may not edit participation tag in different course")

if request.method == "POST":
form = EditParticipationTagForm(add_new, request.POST, instance=ptag)
try:
if form.is_valid():
if "submit" in request.POST or "update" in request.POST:
# Ref: https://stackoverflow.com/q/21458387/3437454
with transaction.atomic():
form.save()

if "submit" in request.POST:
assert add_new
msg = _("New participation tag saved.")
else:
msg = _("Changes saved.")
elif "delete" in request.POST:
ptag.delete()
msg = (_("successfully deleted participation tag '%(tag)s'.")
% {"tag": ptag.name})
else:
raise SuspiciousOperation(_("invalid operation"))

messages.add_message(request, messages.SUCCESS, msg)
return redirect(
"relate-view_participation_tags", pctx.course.identifier)
except IntegrityError:
messages.add_message(
request, messages.ERROR,
_("A participation tag with that name already exists."))

else:
form = EditParticipationTagForm(add_new, instance=ptag)

return render_course_page(pctx, "course/generic-course-form.html", {
"form_description": _("Edit Participation Tag"),
"form": form,
})

# }}}


# {{{ edit_participation_role

class EditParticipationRoleForm(StyledModelForm):
def __init__(self, add_new, *args, **kwargs):
# type: (bool, *Any, **Any) -> None
super(EditParticipationRoleForm, self).__init__(*args, **kwargs)

if add_new:
self.helper.add_input(
Submit("submit", _("Add"), css_class="btn-success"))
else:
self.helper.add_input(
Submit("submit", _("Update"), css_class="btn-success"))
self.helper.add_input(
Submit("delete", _("Delete"), css_class="btn-danger"))

class Meta:
model = ParticipationRole
exclude = ("course",)


@course_view
def view_participation_role_list(pctx):
if not pctx.has_permission(pperm.view_gradebook):
raise PermissionDenied(_("may not edit participation tags"))

participation_roles = list(ParticipationRole.objects.filter(course=pctx.course))

return render_course_page(pctx, "course/participation-role-list.html", {
"participation_roles": participation_roles,
})


@course_view
def edit_participation_role(pctx, prole_id):
# type: (CoursePageContext, int) -> http.HttpResponse
if not pctx.has_permission(pperm.edit_participation_role):
raise PermissionDenied()

request = pctx.request

num_prole_id = int(prole_id)

if num_prole_id == -1:
prole = ParticipationRole(course=pctx.course)
add_new = True
else:
prole = get_object_or_404(ParticipationRole, id=num_prole_id)
add_new = False

if prole.course.id != pctx.course.id:
raise SuspiciousOperation(
"may not edit participation role in different course")

if request.method == "POST":
form = EditParticipationRoleForm(add_new, request.POST, instance=prole)
try:
if form.is_valid():
if "submit" in request.POST or "update" in request.POST:
# Ref: https://stackoverflow.com/q/21458387/3437454
with transaction.atomic():
form.save()

if "submit" in request.POST:
assert add_new
msg = _("New participation role saved.")
else:
msg = _("Changes saved.")
elif "delete" in request.POST:
prole.delete()
msg = (
_("successfully deleted participation role '%(role)s'.")
% {"role": prole.identifier})
else:
raise SuspiciousOperation(_("invalid operation"))

messages.add_message(request, messages.SUCCESS, msg)
return redirect(
"relate-view_participation_roles", pctx.course.identifier)
except IntegrityError:
messages.add_message(
request, messages.ERROR,
_("A participation role with that identifier already exists."))

else:
form = EditParticipationRoleForm(add_new, instance=prole)

return render_course_page(pctx, "course/generic-course-form.html", {
"form_description": _("Edit Participation Role"),
"form": form,
})

# }}}


# vim: foldmethod=marker
49 changes: 49 additions & 0 deletions course/migrations/0115_added_edit_prole_and_ptag_permission.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Generated by Django 3.0.8 on 2020-10-26 08:48

from __future__ import unicode_literals

from django.db import migrations, models


def add_edit_prole_and_ptag_permission(apps, schema_editor):
from course.constants import participation_permission as pperm

ParticipationRolePermission = apps.get_model("course", "ParticipationRolePermission") # noqa

roles_pks = (
ParticipationRolePermission.objects.filter(
permission=pperm.preapprove_participation)
.values_list("role", flat=True)
)

if roles_pks.count():
for pk in roles_pks:
ParticipationRolePermission.objects.get_or_create(
role_id=pk,
permission=pperm.edit_participation_role
)
ParticipationRolePermission.objects.get_or_create(
role_id=pk,
permission=pperm.edit_participation_tag
)


class Migration(migrations.Migration):

dependencies = [
('course', '0114_alter_helptext_for_ptag_and_prole_fix_typo'),
]

operations = [
migrations.AlterField(
model_name='participationpermission',
name='permission',
field=models.CharField(choices=[('edit_course', 'Edit course'), ('use_admin_interface', 'Use admin interface'), ('manage_authentication_tokens', 'Manage authentication tokens'), ('impersonate_role', 'Impersonate role'), ('set_fake_time', 'Set fake time'), ('set_pretend_facility', 'Pretend to be in facility'), ('edit_course_permissions', 'Edit course permissions'), ('view_hidden_course_page', 'View hidden course page'), ('view_calendar', 'View calendar'), ('send_instant_message', 'Send instant message'), ('access_files_for', 'Access files for'), ('included_in_grade_statistics', 'Included in grade statistics'), ('skip_during_manual_grading', 'Skip during manual grading'), ('edit_exam', 'Edit exam'), ('issue_exam_ticket', 'Issue exam ticket'), ('batch_issue_exam_ticket', 'Batch issue exam ticket'), ('view_participant_masked_profile', "View participants' masked profile only"), ('view_flow_sessions_from_role', 'View flow sessions from role'), ('view_gradebook', 'View gradebook'), ('edit_grading_opportunity', 'Edit grading opportunity'), ('assign_grade', 'Assign grade'), ('view_grader_stats', 'View grader stats'), ('batch_import_grade', 'Batch-import grades'), ('batch_export_grade', 'Batch-export grades'), ('batch_download_submission', 'Batch-download submissions'), ('impose_flow_session_deadline', 'Impose flow session deadline'), ('batch_impose_flow_session_deadline', 'Batch-impose flow session deadline'), ('end_flow_session', 'End flow session'), ('batch_end_flow_session', 'Batch-end flow sessions'), ('regrade_flow_session', 'Regrade flow session'), ('batch_regrade_flow_session', 'Batch-regrade flow sessions'), ('recalculate_flow_session_grade', 'Recalculate flow session grade'), ('batch_recalculate_flow_session_grade', 'Batch-recalculate flow sesssion grades'), ('reopen_flow_session', 'Reopen flow session'), ('grant_exception', 'Grant exception'), ('view_analytics', 'View analytics'), ('preview_content', 'Preview content'), ('update_content', 'Update content'), ('use_git_endpoint', 'Use direct git endpoint'), ('use_markup_sandbox', 'Use markup sandbox'), ('use_page_sandbox', 'Use page sandbox'), ('test_flow', 'Test flow'), ('edit_events', 'Edit events'), ('query_participation', 'Query participation'), ('edit_participation', 'Edit participation'), ('preapprove_participation', 'Preapprove participation'), ('edit_participation_role', 'Edit participation role'), ('edit_participation_tag', 'Edit participation tag'), ('manage_instant_flow_requests', 'Manage instant flow requests')], db_index=True, max_length=200, verbose_name='Permission'),
),
migrations.AlterField(
model_name='participationrolepermission',
name='permission',
field=models.CharField(choices=[('edit_course', 'Edit course'), ('use_admin_interface', 'Use admin interface'), ('manage_authentication_tokens', 'Manage authentication tokens'), ('impersonate_role', 'Impersonate role'), ('set_fake_time', 'Set fake time'), ('set_pretend_facility', 'Pretend to be in facility'), ('edit_course_permissions', 'Edit course permissions'), ('view_hidden_course_page', 'View hidden course page'), ('view_calendar', 'View calendar'), ('send_instant_message', 'Send instant message'), ('access_files_for', 'Access files for'), ('included_in_grade_statistics', 'Included in grade statistics'), ('skip_during_manual_grading', 'Skip during manual grading'), ('edit_exam', 'Edit exam'), ('issue_exam_ticket', 'Issue exam ticket'), ('batch_issue_exam_ticket', 'Batch issue exam ticket'), ('view_participant_masked_profile', "View participants' masked profile only"), ('view_flow_sessions_from_role', 'View flow sessions from role'), ('view_gradebook', 'View gradebook'), ('edit_grading_opportunity', 'Edit grading opportunity'), ('assign_grade', 'Assign grade'), ('view_grader_stats', 'View grader stats'), ('batch_import_grade', 'Batch-import grades'), ('batch_export_grade', 'Batch-export grades'), ('batch_download_submission', 'Batch-download submissions'), ('impose_flow_session_deadline', 'Impose flow session deadline'), ('batch_impose_flow_session_deadline', 'Batch-impose flow session deadline'), ('end_flow_session', 'End flow session'), ('batch_end_flow_session', 'Batch-end flow sessions'), ('regrade_flow_session', 'Regrade flow session'), ('batch_regrade_flow_session', 'Batch-regrade flow sessions'), ('recalculate_flow_session_grade', 'Recalculate flow session grade'), ('batch_recalculate_flow_session_grade', 'Batch-recalculate flow sesssion grades'), ('reopen_flow_session', 'Reopen flow session'), ('grant_exception', 'Grant exception'), ('view_analytics', 'View analytics'), ('preview_content', 'Preview content'), ('update_content', 'Update content'), ('use_git_endpoint', 'Use direct git endpoint'), ('use_markup_sandbox', 'Use markup sandbox'), ('use_page_sandbox', 'Use page sandbox'), ('test_flow', 'Test flow'), ('edit_events', 'Edit events'), ('query_participation', 'Query participation'), ('edit_participation', 'Edit participation'), ('preapprove_participation', 'Preapprove participation'), ('edit_participation_role', 'Edit participation role'), ('edit_participation_tag', 'Edit participation tag'), ('manage_instant_flow_requests', 'Manage instant flow requests')], db_index=True, max_length=200, verbose_name='Permission'),
),
migrations.RunPython(add_edit_prole_and_ptag_permission),
]
2 changes: 2 additions & 0 deletions course/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,8 @@ def add_instructor_permissions(role):
rpm(role=role, permission=pp.edit_events).save()
rpm(role=role, permission=pp.manage_instant_flow_requests).save()
rpm(role=role, permission=pp.preapprove_participation).save()
rpm(role=role, permission=pp.edit_participation_tag).save()
rpm(role=role, permission=pp.edit_participation_role).save()

add_teaching_assistant_permissions(role)

Expand Down
20 changes: 12 additions & 8 deletions course/templates/course/course-base.html
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,26 @@
</li>
{% endif %}

{% if pperm.view_gradebook %}
{% if pperm.view_gradebook or pperm.edit_participation %}
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">{% trans "Grading" context "menu item" %}<b class="caret"></b></a>
<ul class="dropdown-menu">
{% if pperm.edit_participation or pperm.query_participation %}
<li role="presentation" class="dropdown-header">{% trans "Participations" %}</li>
<li><a href="{% url "relate-view_participant_list" course.identifier %}">{% trans "List of participants" %}</a></li>
<li><a href="{% url "relate-view_participation_roles" course.identifier %}">{% trans "Participation roles" %}</a></li>
<li><a href="{% url "relate-view_participation_tags" course.identifier %}">{% trans "Participation tags" %}</a></li>
{% if pperm.query_participation %}
<li><a href="{% url "relate-query_participations" course.identifier %}">{% trans "Query participations" context "menu item" %}</a></li>
{% endif %}
<li role="presentation" class="divider"></li>
{% endif %}
{% if pperm.view_analytics %}
<li><a href="{% url "relate-flow_list" course.identifier %}">{% trans "Analytics Overview" %}</a></li>
{% endif %}

{% if pperm.view_gradebook %}
<li role="presentation" class="divider"></li>
<li role="presentation" class="dropdown-header">{% trans "Grade Book" %}</li>
<li><a href="{% url "relate-view_participant_list" course.identifier %}">{% trans "List of Participants" %}</a></li>
<li><a href="{% url "relate-view_grading_opportunity_list" course.identifier %}">{% trans "List of Grading Opportunities" %}</a></li>
<li><a href="{% url "relate-view_gradebook" course.identifier %}">{% trans "Grade book" %}</a></li>
{% if pperm.batch_export_grade %}
Expand Down Expand Up @@ -139,7 +147,7 @@
</li>
{% endif %}

{% if pperm.query_participation or pperm.manage_instant_flow_requests or pperm.preapprove_participation %}
{% if pperm.manage_instant_flow_requests or pperm.preapprove_participation %}
{% if not pperm.view_participant_masked_profile %}
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">{% trans "Instructor" context "menu item" %}<b class="caret"></b></a>
Expand All @@ -148,10 +156,6 @@
{% if pperm.preapprove_participation %}
<li><a href="{% url "relate-create_preapprovals" course.identifier %}">{% trans "Preapprove enrollments" context "menu item" %}</a></li>
{% endif %}
{% if pperm.query_participation %}
<li><a href="{% url "relate-query_participations" course.identifier %}">{% trans "Query participations" context "menu item" %}</a></li>
{% endif %}

{% if pperm.manage_instant_flow_requests %}
<li role="presentation" class="divider"></li>
<li role="presentation" class="dropdown-header">{% trans "Instant flow requests" %}</li>
Expand Down
2 changes: 1 addition & 1 deletion course/templates/course/gradebook-participant-list.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
{% endblock %}

{% block content %}
<h1>{% trans "List of Participants" %}</h1>
<h1>{% trans "List of participants" %}</h1>

<a href="{% url "relate-edit_participation" course.identifier -1 %}" class="btn btn-default">{% trans "Add participant" %}</a>

Expand Down
21 changes: 21 additions & 0 deletions course/templates/course/participation-role-list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{% extends "course/course-base.html" %}
{% load i18n %}

{% load static %}

{% block title %}
{% trans "Participation Roles" %} - {{ relate_site_name }}
{% endblock %}

{% block header_extra %}
{% include "datatables-header.html" %}
{% endblock %}

{% block content %}
<h1>{% trans "Participation roles" %}</h1>

<a href="{% url "relate-edit_participation_role" course.identifier -1 %}" class="btn btn-default">{% trans "Add participation role" %}</a>

{% include "course/participation-role-table.html" with participation_roles=participation_roles %}

{% endblock %}
Loading