Skip to content

Commit

Permalink
Merge pull request #126 from planetterp/perms-planetterp-admin
Browse files Browse the repository at this point in the history
  • Loading branch information
nsandler1 authored Jun 19, 2023
2 parents 7cbd04f + 2403962 commit f620f04
Show file tree
Hide file tree
Showing 11 changed files with 48 additions and 30 deletions.
15 changes: 15 additions & 0 deletions home/migrations/0011_user_is_planetterp_admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('home', '0010_initial_data'),
]

operations = [
migrations.AlterModelOptions(
name='user',
options={'permissions': [('mod', 'Can take any planetterp site moderator actions')]},
),
]
15 changes: 11 additions & 4 deletions home/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,11 +331,9 @@ class User(AbstractUser):
objects = UserManager()

send_review_email = BooleanField(default=True)

# accounts which are from ourumd are given an unusable password so nobody
# can log in to the accounts
from_ourumd = BooleanField(default=False)

username = CharField(
max_length=22,
unique=True,
Expand All @@ -351,7 +349,6 @@ class User(AbstractUser):
"unique": "A user with that username already exists."
}
)

email = EmailField(
unique=True,
null=True,
Expand All @@ -366,7 +363,6 @@ class User(AbstractUser):
)
}
)

password = CharField(
max_length=128,
validators=[
Expand All @@ -377,6 +373,17 @@ class User(AbstractUser):
}
)

class Meta:
# planetterp admins are a level between staff users and normal users:
# admins can view the admin panel and take all actions theiren, but
# cannot view the django admin panel.
# Essentially, this role is for site admins which should not have access
# to the prod db, which the django admin panel grants to a moderate
# degree.
permissions = [
("mod", "Can take any planetterp site moderator actions")
]

# Workaround to force CharField to store empty values as NULL instead of ''
# https://stackoverflow.com/a/38621160
def save(self, *args, **kwargs):
Expand Down
8 changes: 4 additions & 4 deletions home/tables/columns.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def grade_to_element(self, grade):

def render(self, value: dict):
review = value.pop("review")
is_staff = value.pop("is_staff")
is_planetterp_admin = value.pop("is_planetterp_admin")

column_html = ""
if review.professor.slug:
Expand Down Expand Up @@ -80,7 +80,7 @@ def render(self, value: dict):

# wrap long usernames to avoid increasing the information column width
column_html += '<span style="white-space: normal; word-break: break-all;">'
if is_staff and review.user:
if is_planetterp_admin and review.user:
if review.anonymous:
column_html += '''
<span class="noselect" data-toggle="tooltip" data-placement="right" title="This reviewer posted anonymously">
Expand Down Expand Up @@ -110,12 +110,12 @@ def render(self, value: dict):
if review.created_at.date() >= date(2020, 3, 10) and review.created_at.date() <= date(2021, 8, 30):
column_html += ' <i class="fas fa-head-side-mask" data-toggle="tooltip" data-placement="right" title="This review was submitted while most classes were online during the COVID-19 pandemic. It may not be indicative of a regular semester."></i>'

if not review.user or (review.anonymous and not is_staff):
if not review.user or (review.anonymous and not is_planetterp_admin):
username = "Anonymous"
else:
username = review.user.username

if is_staff:
if is_planetterp_admin:
column_html += '''
<br/ >
<span>
Expand Down
4 changes: 2 additions & 2 deletions home/tables/reviews_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def get_data(self, reviews: QuerySet[Review]):
if ReviewsTableColumn.INFORMATION in self.columns:
formatted_data['information'] = {
"review": review,
"is_staff": self.request.user.is_staff
"is_planetterp_admin": self.request.user.has_perm("home.mod")
}
if ReviewsTableColumn.REVIEW in self.columns:
formatted_data['review'] = {"review": review}
Expand Down Expand Up @@ -87,7 +87,7 @@ def __init__(self, reviews, request, *args, **kwargs):
)

self.columns = [ReviewsTableColumn.INFORMATION, ReviewsTableColumn.REVIEW]
if request.user.is_staff:
if request.user.has_perm("home.mod"):
self.columns.append(ReviewsTableColumn.ACTION)

kwargs = {"empty_text": empty_text}
Expand Down
4 changes: 2 additions & 2 deletions home/templates/base_main.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
<link rel="stylesheet" type="text/css" href="{% static 'css/progressbar.css' %}">
<link rel="stylesheet" type="text/css" href="{% static 'fontawesome-5.15.3/css/all.min.css' %}">

{% if user and user.is_staff %}
{% if user and perms.home.mod %}
<script type="text/javascript" src="{% static 'js/admin-action.js' %}"></script>
{% endif %}

Expand Down Expand Up @@ -151,7 +151,7 @@
</ul>

<ul class="navbar-nav navbar-right mr-3">
{% if user.is_staff %}
{% if perms.home.mod %}
<li class="nav-item">
<a style="color: #ffc107;" class="nav-link" href="{% url 'admin' %}#reviews" title="Admin Page">
<span id="unverified_count" class="badge badge-pill badge-warning">{% unverified_count %}</span>
Expand Down
2 changes: 1 addition & 1 deletion home/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ <h4>Recent reviews</h4>
django can't handle parenthesis in if statements for order of operations :/ so
split into multiple cases
-->
{% if user.is_staff and review.user %}
{% if perms.home.mod and review.user %}
{{ review.user.username }}
{% elif review.user and not review.anonymous %}
{{ review.user.username }}
Expand Down
6 changes: 3 additions & 3 deletions home/templates/professor.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<div class="container mw-100 px-5">
<div class="row">
<div class="col-xs-12 col-sm-6 col-md-6 offset-md-1">
{% if user.is_staff %}
{% if perms.home.mod %}
<div class="professor-header input-group">
<h1 class="input-group">
<span id="professor-name"><strong>{{ professor.name }}</strong></span>
Expand Down Expand Up @@ -130,7 +130,7 @@ <h4 class="modal-title" id="grades-modal-label">Grades</h4>
<script type="text/javascript">
var num_reviews = parseInt("{{ num_reviews }}");
var average_rating = {% if professor.average_rating %} {{ professor.average_rating }} {% else %} null {% endif %};
var is_admin = {{ user.is_staff|yesno:"true,false" }};
var is_mod = {{ perms.home.mod|yesno:"true,false" }};

$(function() {
initializeRateYo(3, "review");
Expand All @@ -141,7 +141,7 @@ <h4 class="modal-title" id="grades-modal-label">Grades</h4>
generateProfessorStats();
}

if (is_admin) {
if (is_mod) {
initalizeAutoComplete('{{ csrf_token }}');
}
});
Expand Down
8 changes: 3 additions & 5 deletions home/views/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from django.views import View
from django.http import JsonResponse
from django.template.context_processors import csrf
from django.contrib.auth.mixins import UserPassesTestMixin
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.urls import reverse
from django.utils.safestring import mark_safe

Expand All @@ -21,10 +21,8 @@
from home.utils import send_email, _ttl_cache, create_autoslug
from planetterp import config

class Admin(UserPassesTestMixin, View):

def test_func(self):
return self.request.user.is_staff
class Admin(PermissionRequiredMixin, View):
permission_required = "home.mod"

def get(self, request):
reviews = (
Expand Down
12 changes: 5 additions & 7 deletions home/views/basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from django.views import View
from django.views.generic import TemplateView, RedirectView, ListView
from django.http import HttpResponse, Http404
from django.contrib.auth.mixins import UserPassesTestMixin
from django.contrib.auth.mixins import PermissionRequiredMixin

from home.models import Organization, Professor, Course, Review, Grade, User
from home.tables.reviews_table import VerifiedReviewsTable, ProfileReviewsTable
Expand Down Expand Up @@ -128,22 +128,20 @@ def post(self, request):

return JsonResponse(context)

class RecomputeTTLCache(UserPassesTestMixin, View):
def test_func(self):
return self.request.user.is_staff
class RecomputeTTLCache(PermissionRequiredMixin, View):
permission_required = "home.mod"

def post(self, _request):
recompute_ttl_cache()
return HttpResponse()

class UserProfile(UserPassesTestMixin, View):
class UserProfile(PermissionRequiredMixin, View):
# as all accounts have the option to still leave anonymous reviews, only
# allow admins to view individual user profiles for now.
#
# We may want to allow people to view a subset of other user's profiles
# in the future, which would show only the public reviews of that user.
def test_func(self):
return self.request.user.is_staff
permission_required = "home.mod"

def get(self, request, user_id):
# if a user clicks on a link to their own profile, redirect them to
Expand Down
2 changes: 1 addition & 1 deletion home/views/endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def get(self, request):
value_dict['name'] = result.name

data = {
"label": f"{result}" if request.user.is_staff else f"{result.name}",
"label": f"{result}" if request.user.has_perm("home.mod") else f"{result.name}",
"result": value_dict
}

Expand Down
2 changes: 1 addition & 1 deletion home/views/professor.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def get(self, request, slug):
"num_reviews": reviews.count()
}

if request.user.is_staff:
if request.user.has_perm("home.mod"):
edit_professor_form = ProfessorUpdateForm(professor, instance=professor)
unverify_professor_form = ProfessorUnverifyForm(professor.pk)
merge_professor_form = ProfessorMergeForm(request)
Expand Down

0 comments on commit f620f04

Please sign in to comment.