Skip to content

Commit

Permalink
temp working commit
Browse files Browse the repository at this point in the history
  • Loading branch information
alanzhu0 committed Mar 31, 2024
1 parent ffdd800 commit b4bca0e
Show file tree
Hide file tree
Showing 24 changed files with 465 additions and 331 deletions.
4 changes: 2 additions & 2 deletions intranet/apps/announcements/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@


class AnnouncementAdmin(admin.ModelAdmin):
list_display = ("title", "user", "author", "added")
list_filter = ("added", "updated")
list_display = ("title", "user", "author", "activity", "added")
list_filter = ("added", "updated", "activity")
ordering = ("-added",)
raw_id_fields = ("user",)

Expand Down
23 changes: 19 additions & 4 deletions intranet/apps/announcements/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@

from ..users.forms import SortedTeacherMultipleChoiceField
from .models import Announcement, AnnouncementRequest
from ..eighth.models import EighthActivity

import logging

logger = logging.getLogger(__name__)

class AnnouncementForm(forms.ModelForm):
"""A form for generating an announcement."""
Expand All @@ -29,17 +33,28 @@ class ClubAnnouncementForm(forms.ModelForm):

def __init__(self, user, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["activity"].queryset = user.officer_for_set

if user.is_announcements_admin:
self.fields["activity"].queryset = EighthActivity.objects.filter(subscriptions_enabled=True)
elif user.is_club_officer:
self.fields["activity"].queryset = EighthActivity.objects.filter(subscriptions_enabled=True, officers=user)
elif user.is_eighth_sponsor:
self.fields["activity"].queryset = EighthActivity.objects.filter(subscriptions_enabled=True, sponsors=user)
else:
self.fields["activity"].queryset = []
self.fields["activity"].required = True

if "instance" in kwargs: # Don't allow changing the activity once the announcement has been created
self.fields["activity"].widget.attrs["disabled"] = True
self.fields["activity"].required = False

expiration_date = forms.DateTimeInput()
update_added_date = forms.BooleanField(required=False, label="Update Added Date")

class Meta:
model = Announcement
fields = ["title", "author", "content", "activity", "expiration_date", "update_added_date"]
fields = ["activity", "title", "content", "expiration_date"]
help_texts = {
"expiration_date": "By default, announcements expire after two weeks. To change this, click in the box above.",
"update_added_date": "If this announcement has already been added, update the added date to now so that the announcement is pushed to the top. If this option is not selected, the announcement will stay in its current position.",
}


Expand Down
12 changes: 8 additions & 4 deletions intranet/apps/announcements/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from ...utils.date import get_date_range_this_year, is_current_year
from ...utils.deletion import set_historical_user
from ...utils.html import nullify_links

from ..eighth.models import EighthActivity


Expand Down Expand Up @@ -90,7 +89,7 @@ class Announcement(models.Model):
The title of the announcement
content
The HTML content of the news post
authors
author
The name of the author
added
The date the announcement was added
Expand Down Expand Up @@ -151,6 +150,11 @@ def is_club_announcement(self):

def is_visible(self, user):
return self in Announcement.objects.visible_to_user(user)

def can_modify(self, user):
return user.is_announcements_admin or self.is_club_announcement and (
self.is_visible_submitter(user) or user in self.activity.user_sponsors
)

# False, not None. This can be None if no AnnouncementRequest exists for this Announcement,
# and we should not reevaluate in that case.
Expand All @@ -165,13 +169,13 @@ def announcementrequest(self):

def is_visible_requester(self, user):
try:
return self.announcementrequest_set.filter(teachers_requested__id=user.id).exists()
return self.announcementrequest_set.filter(teachers_requested=user).exists()
except get_user_model().DoesNotExist:
return False

def is_visible_submitter(self, user):
try:
return (self.announcementrequest and user.id == self.announcementrequest.user_id) or self.user_id == user.id
return self.user == user or self.announcementrequest and user == self.announcementrequest.user
except get_user_model().DoesNotExist:
return False

Expand Down
10 changes: 4 additions & 6 deletions intranet/apps/announcements/notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,12 @@ def announcement_posted_email(request, obj, send_all=False):
.objects.filter(user_type="student", graduation_year__gte=get_senior_graduation_year())
.union(get_user_model().objects.filter(user_type__in=["teacher", "counselor"]))
)
elif obj.club:
filter = Q(subscribed_to_set__contains=obj.club) & (
Q(user_type="student") & Q(graduation_year__gte=get_senior_graduation_year()) | Q(user_type__in=["teacher", "counselor"])
)
elif obj.activity:
subject = f"Club Announcement for {obj.activity.name}: {obj.title}"
users = (
get_user_model()
.objects.filter(user_type="student", graduation_year__gte=get_senior_graduation_year(), subscribed_to_set__contains=obj.club)
.union(get_user_model().objects.filter(user_type__in=["teacher", "counselor"], subscribed_to_set__contains=obj.club))
.objects.filter(user_type="student", graduation_year__gte=get_senior_graduation_year(), subscribed_to_set__contains=obj.activity)
.union(get_user_model().objects.filter(user_type__in=["teacher", "counselor"], subscribed_to_set__contains=obj.activity))
)

else:
Expand Down
3 changes: 2 additions & 1 deletion intranet/apps/announcements/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
re_path(r"^/club$", views.view_club_announcements, name="club_announcements"),
re_path(r"^/add$", views.add_announcement_view, name="add_announcement"),
re_path(r"^/request$", views.request_announcement_view, name="request_announcement"),
re_path(r"^/club/post$", views.post_club_announcement_view, name="post_club_announcement"),
re_path(r"^/club/add$", views.add_club_announcement_view, name="add_club_announcement"),
re_path(r"^/club/modify/(?P<announcement_id>\d+)$", views.modify_club_announcement_view, name="modify_club_announcement"),
re_path(r"^/request/success$", views.request_announcement_success_view, name="request_announcement_success"),
re_path(r"^/request/success_self$", views.request_announcement_success_self_view, name="request_announcement_success_self"),
re_path(r"^/approve/(?P<req_id>\d+)$", views.approve_announcement_view, name="approve_announcement"),
Expand Down
52 changes: 41 additions & 11 deletions intranet/apps/announcements/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,8 @@
from ..groups.models import Group
from .forms import AnnouncementAdminForm, AnnouncementEditForm, AnnouncementForm, AnnouncementRequestForm, ClubAnnouncementForm
from .models import Announcement, AnnouncementRequest
from .notifications import (
admin_request_announcement_email,
announcement_approved_email,
announcement_posted_email,
announcement_posted_twitter,
request_announcement_email,
)
from .notifications import (admin_request_announcement_email, announcement_approved_email, announcement_posted_email, announcement_posted_twitter,
request_announcement_email)

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -131,7 +126,9 @@ def request_announcement_view(request):
return render(request, "announcements/request.html", {"form": form, "action": "add"})


def post_club_announcement_view(request):
@login_required
@deny_restricted
def add_club_announcement_view(request):
if request.method == "POST":
form = ClubAnnouncementForm(request.user, request.POST)

Expand All @@ -143,14 +140,47 @@ def post_club_announcement_view(request):

obj.save()

messages.success(request, "Successfully posted announcement.")
messages.success(request, "Successfully posted club announcement.")
return redirect("club_announcements")
else:
messages.error(request, "Error adding announcement")
messages.error(request, "Error adding club announcement")
else:
form = ClubAnnouncementForm(request.user)
return render(request, "announcements/club-request.html", {"form": form, "action": "add"})

@login_required
@deny_restricted
def modify_club_announcement_view(request, announcement_id):
announcement = get_object_or_404(Announcement, id=announcement_id)

if not announcement.is_club_announcement:
messages.error(request, "This announcement is not a club announcement.")
return redirect("club_announcements")

if not announcement.can_modify(request.user):
messages.error(request, "You do not have permission to modify this club announcement.")
return redirect("club_announcements")

if request.method == "POST":
form = ClubAnnouncementForm(request.user, request.POST, instance=announcement)

if form.is_valid():
obj = form.save(commit=True)
obj.user = request.user
obj.activity = announcement.activity
# SAFE HTML
obj.content = safe_html(obj.content)

obj.save()

messages.success(request, "Successfully modified club announcement.")
return redirect("club_announcements")
else:
messages.error(request, "Error modifying club announcement")
else:
form = ClubAnnouncementForm(request.user, instance=announcement)
return render(request, "announcements/club-request.html", {"form": form, "action": "modify"})


@login_required
@deny_restricted
Expand Down Expand Up @@ -355,7 +385,7 @@ def modify_announcement_view(request, announcement_id=None):
logger.info("Admin %s modified announcement: %s (%s)", request.user, announcement, announcement.id)
return redirect("index")
else:
messages.error(request, "Error adding announcement")
messages.error(request, "Error modifying announcement")
else:
announcement = get_object_or_404(Announcement, id=announcement_id)
form = AnnouncementEditForm(instance=announcement)
Expand Down
22 changes: 13 additions & 9 deletions intranet/apps/dashboard/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,11 +239,11 @@ def get_announcements_list(request, context):

# Load information on the user who posted the announcement
# Unless the announcement has a custom author (some do, but not all), we will need the user information to construct the byline,
announcements = announcements.select_related("user")
announcements = announcements.select_related("user", "activity")

# We may query the announcement request multiple times while checking if the user submitted or approved the announcement.
# prefetch_related() will still make a separate query for each request, but the results are cached if we check them multiple times
announcements = announcements.prefetch_related("announcementrequest_set")
announcements = announcements.prefetch_related("announcementrequest_set", "groups")

if context["events_admin"] and context["show_all"]:
events = Event.objects.all()
Expand All @@ -255,6 +255,8 @@ def get_announcements_list(request, context):
midnight = timezone.localtime().replace(hour=0, minute=0, second=0, microsecond=0)
events = Event.objects.visible_to_user(user).filter(time__gte=midnight, show_on_dashboard=True)

events = events.select_related("user").prefetch_related("groups")

items = sorted(chain(announcements, events), key=lambda item: (item.pinned, item.added))
items.reverse()

Expand All @@ -266,7 +268,8 @@ def split_club_announcements(items):

for item in items:
if item.dashboard_type == "announcement" and item.is_club_announcement:
club.append(item)
if item.activity.subscriptions_enabled:
club.append(item)
else:
standard.append(item)

Expand All @@ -277,12 +280,13 @@ def filter_club_announcements(user, user_hidden_announcements, club_items):
visible, hidden, unsubscribed = [], [], []

for item in club_items:
if user not in item.activity.subscribers.all():
unsubscribed.append(item)
elif item.id in user_hidden_announcements:
hidden.append(item)
else:
visible.append(item)
if item.activity.subscriptions_enabled:
if user not in item.activity.subscribers.all():
unsubscribed.append(item)
elif item.id in user_hidden_announcements:
hidden.append(item)
else:
visible.append(item)

return visible, hidden, unsubscribed

Expand Down
14 changes: 14 additions & 0 deletions intranet/apps/eighth/forms/admin/activities.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ def __init__(self, *args, **kwargs):

self.fields["presign"].label = "2 day pre-signup"
self.fields["default_capacity"].help_text = "Overrides the sum of each room's capacity above, if set."
self.fields["subscriptions_enabled"].label = "Enable club announcements"
self.fields["subscriptions_enabled"].help_text = "Allow students to subscribe to receive announcements for this activity through Ion."
self.fields["officers"].help_text = "Student officers can send club announcements to subscribers."

# These fields are rendered on the right of the page on the edit activity page.
self.right_fields = set(
Expand All @@ -153,6 +156,14 @@ def __init__(self, *args, **kwargs):
]
)

self.club_announcements_fields = set(
[
"subscriptions_enabled",
"officers",
"subscribers",
]
)

class Meta:
model = EighthActivity
fields = [
Expand Down Expand Up @@ -182,6 +193,9 @@ class Meta:
"fri_a",
"fri_b",
"admin_comments",
"subscriptions_enabled",
"officers",
"subscribers",
]
widgets = {
"description": forms.Textarea(attrs={"rows": 9, "cols": 46}),
Expand Down
21 changes: 21 additions & 0 deletions intranet/apps/eighth/migrations/0069_alter_eighthsponsor_user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 3.2.25 on 2024-03-30 04:11

from django.conf import settings
from django.db import migrations, models
import intranet.utils.deletion


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('eighth', '0068_auto_20240213_1938'),
]

operations = [
migrations.AlterField(
model_name='eighthsponsor',
name='user',
field=models.OneToOneField(blank=True, null=True, on_delete=intranet.utils.deletion.set_historical_user, related_name='sponsor_obj', to=settings.AUTH_USER_MODEL),
),
]
10 changes: 9 additions & 1 deletion intranet/apps/eighth/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class EighthSponsor(AbstractBaseEighthModel):

first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
user = models.OneToOneField(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=set_historical_user)
user = models.OneToOneField(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=set_historical_user, related_name="sponsor_obj")
department = models.CharField(max_length=20, choices=DEPARTMENTS, default="general")
full_time = models.BooleanField(default=True)
online_attendance = models.BooleanField(default=True)
Expand Down Expand Up @@ -419,6 +419,14 @@ def is_popular(self) -> bool:
"""
return self.frequent_users.count() > (settings.SIMILAR_THRESHOLD * 2)

@property
def user_sponsors(self):
"""Returns the User objects of the sponsors of this activity.
Returns:
The User objects of the sponsors of this activity.
"""
return {sponsor.user for sponsor in self.sponsors.all() if sponsor.user}

class Meta:
verbose_name_plural = "eighth activities"

Expand Down
4 changes: 2 additions & 2 deletions intranet/apps/users/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -929,7 +929,7 @@ def is_eighth_sponsor(self) -> bool:
return EighthSponsor.objects.filter(user=self).exists()

@property
def is_eighth_officer(self) -> bool:
def is_club_officer(self) -> bool:
"""Checks if this user is an officer of an eighth period activity.
Returns:
Expand Down Expand Up @@ -1270,7 +1270,7 @@ def attribute_is_public(self, permission: str) -> bool:


PERMISSIONS_NAMES = {
prefix: [name[len(prefix) + 1 :] for name in dir(UserProperties) if name.startswith(prefix + "_")] for prefix in ["self", "parent"]
prefix: [name[len(prefix) + 1:] for name in dir(UserProperties) if name.startswith(prefix + "_")] for prefix in ["self", "parent"]
}


Expand Down
4 changes: 4 additions & 0 deletions intranet/static/css/dark/dashboard.scss
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,7 @@ a.button {
color: white !important;
}
}

a.club-announcement-meta-link:hover {
color: rgb(196, 196, 196) !important;
}
Loading

0 comments on commit b4bca0e

Please sign in to comment.