Skip to content

Commit

Permalink
Merge branch 'develop' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
JasonLovesDoggo authored Sep 1, 2024
2 parents 1f8b5e6 + 0962afd commit d6ded90
Show file tree
Hide file tree
Showing 66 changed files with 1,157 additions and 853 deletions.
10 changes: 7 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
default_language_version:
python: python
repos:
- repo: https://github.com/psf/black
rev: 24.2.0
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.6.3
hooks:
- id: black
# Run the linter.
- id: ruff
args: [ --fix ]
# Run the formatter.
- id: ruff-format
- repo: https://github.com/pycqa/isort
rev: 5.13.2
hooks:
Expand Down
90 changes: 29 additions & 61 deletions core/admin.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import django.db
from django.contrib import messages
from django.contrib import admin, messages
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin as DjangoUserAdmin
from django.contrib.flatpages.admin import FlatPageAdmin
from django.contrib.flatpages.models import FlatPage
from django.contrib.messages import constants as messages
from django.db.models import Q
from django.forms import Textarea
from django.urls import reverse
from django.utils.html import format_html
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
Expand All @@ -25,7 +25,22 @@
UserCreationForm,
)
from .models import Comment, StaffMember
from .utils.actions import *
from .utils.actions import (
approve_comments,
archive_page,
resend_approval_email,
reset_club_execs,
reset_club_president,
send_notif_singleday,
send_test_notif,
set_club_active,
set_club_unactive,
set_post_archived,
set_post_unarchived,
unapprove_comments,
)
from .utils.admin import generic_post_formfield_for_manytomany
from .utils.announcements import request_announcement_approval
from .utils.filters import (
BlogPostAuthorListFilter,
OrganizationListFilter,
Expand Down Expand Up @@ -58,7 +73,10 @@ class TermAdmin(admin.ModelAdmin):
inlines = [
CourseInline,
]
list_display = ["name", "timetable_format", "start_date", "end_date"]
list_display = ["name", "timetable_format", "start_date", "end_date", "is_frozen"]
list_filter = ["timetable_format", "is_frozen"]
ordering = ["is_frozen", "-start_date", "-end_date"]

form = TermAdminForm


Expand Down Expand Up @@ -409,17 +427,7 @@ def formfield_for_foreignkey(self, db_field, request, **kwargs):
return super().formfield_for_foreignkey(db_field, request, **kwargs)

def formfield_for_manytomany(self, db_field, request, **kwargs):
if db_field.name == "tags":
kwargs["queryset"] = (
models.Tag.objects.filter(
Q(organization=None) | Q(organization__execs=request.user)
)
.distinct()
.order_by("name")
)
if request.user.is_superuser:
kwargs["queryset"] = models.Tag.objects.all().order_by("name")
return super().formfield_for_manytomany(db_field, request, **kwargs)
return generic_post_formfield_for_manytomany(self, db_field, request, **kwargs)

def has_change_permission(self, request, obj=None):
if (
Expand Down Expand Up @@ -452,35 +460,14 @@ def save_model(self, request, obj, form, change):
notify_supervisors = True

self.message_user(
request, f"Successfully sent announcement for review."
request, "Successfully sent announcement for review."
)
obj.status = "p" if obj.status != "d" else "d"

super().save_model(request, obj, form, change)

if notify_supervisors:
for teacher in obj.organization.supervisors.all():
email_template_context = {
"teacher": teacher,
"announcement": obj,
"review_link": settings.SITE_URL
+ reverse("admin:core_announcement_change", args=(obj.pk,)),
}

send_mail(
f"[ACTION REQUIRED] An announcement for {obj.organization.name} needs your approval.",
render_to_string(
"core/email/verify_announcement.txt",
email_template_context,
),
None,
[teacher.email],
bcc=settings.ANNOUNCEMENT_APPROVAL_BCC_LIST,
html_message=render_to_string(
"core/email/verify_announcement.html",
email_template_context,
),
)
request_announcement_approval(obj)


class BlogPostAdmin(PostAdmin):
Expand Down Expand Up @@ -514,17 +501,7 @@ def get_changeform_initial_data(self, request):
return {"author": request.user.pk}

def formfield_for_manytomany(self, db_field, request, **kwargs):
if db_field.name == "tags":
kwargs["queryset"] = (
models.Tag.objects.filter(
Q(organization=None) | Q(organization__execs=request.user)
)
.distinct()
.order_by("name")
)
if request.user.is_superuser:
kwargs["queryset"] = models.Tag.objects.all().order_by("name")
return super().formfield_for_manytomany(db_field, request, **kwargs)
return generic_post_formfield_for_manytomany(self, db_field, request, **kwargs)


class ExhibitAdmin(PostAdmin):
Expand Down Expand Up @@ -583,17 +560,7 @@ def get_form(self, request, obj=None, **kwargs):
return super().get_form(request, obj, **kwargs)

def formfield_for_manytomany(self, db_field, request, **kwargs):
if db_field.name == "tags":
kwargs["queryset"] = (
models.Tag.objects.filter(
Q(organization=None) | Q(organization__execs=request.user)
)
.distinct()
.order_by("name")
)
if request.user.is_superuser:
kwargs["queryset"] = models.Tag.objects.all().order_by("name")
return super().formfield_for_manytomany(db_field, request, **kwargs)
return generic_post_formfield_for_manytomany(self, db_field, request, **kwargs)

def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "organization":
Expand Down Expand Up @@ -713,7 +680,8 @@ class CommentAdmin(admin.ModelAdmin):
actions_on_bottom = True
date_hierarchy = "created_at"

def likes(self, obj: Comment):
@staticmethod
def likes(obj: Comment):
return obj.like_count

def get_queryset(self, request):
Expand Down
1 change: 1 addition & 0 deletions core/api/serializers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# ruff: noqa: F403
from .announcement import *
from .blogpost import *
from .course import *
Expand Down
1 change: 0 additions & 1 deletion core/api/serializers/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ def get_gravatar_url(obj):
return gravatar_url(obj.email)

class Meta:

model = User
fields = [
"id",
Expand Down
30 changes: 29 additions & 1 deletion core/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,35 @@

from .v3.objects.main import ObjectList, ObjectNew, ObjectRetrieve, ObjectSingle
from .v3.views.user import UserDeleteView, UserRestoreView
from .views import *
from .views import (
AnnouncementListAll,
AnnouncementListMyFeed,
ApiOrganizationList,
APIVersion,
Banners,
EventsList,
Feeds,
MartorImageUpload,
NotificationsNew,
NotifToken,
OrganizationDetail,
TermCurrent,
TermCurrentSchedule,
TermDetail,
TermList,
TermSchedule,
TermScheduleWeek,
TimetableDetails,
TimetableList,
TimetableSchedule,
UserDetail,
UserMe,
UserMeInternal,
UserMeSchedule,
UserMeScheduleWeek,
UserMeTimetable,
staff,
)

router = SimpleRouter()

Expand Down
3 changes: 0 additions & 3 deletions core/api/utils/__init__.py

This file was deleted.

2 changes: 1 addition & 1 deletion core/api/utils/last_modified.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

class GenericAPIViewWithLastModified:
def get_last_modified(self):
raise NotImplemented()
raise NotImplementedError()

def get(self, *args, **kwargs):
resp = super().get(*args, **kwargs)
Expand Down
56 changes: 35 additions & 21 deletions core/api/utils/polymorphism.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,31 @@
from __future__ import annotations

from functools import lru_cache
from json import JSONDecodeError
from typing import Any, Callable, Dict, Iterable, List, Literal, Optional, Protocol, Set
from typing import Any, Callable, Dict, Iterable, List, Optional, Protocol, Set

from django.conf import settings
from django.core.exceptions import BadRequest
from django.db.models import Model, Q
from django.shortcuts import get_object_or_404
from memoization import cached
from rest_framework import generics
from rest_framework.serializers import BaseSerializer

from core.api.v3.objects import *
from core.api.v3.objects import (
AnnouncementProvider,
BlogPostProvider,
CommentProvider,
CourseProvider,
EventProvider,
ExhibitProvider,
FlatPageProvider,
LikeProvider,
OrganizationProvider,
TagProvider,
TermProvider,
TimetableProvider,
UserProvider,
)
from core.api.v3.objects.base import BaseProvider
from core.utils.types import APIObjOperations

Expand Down Expand Up @@ -60,23 +74,23 @@ def get_path_by_provider(provider: BaseProvider) -> str:
][0]


providers: Dict[str, BaseProvider] = (
{ # k = request type (param passed in url), v = provider class
"announcement": AnnouncementProvider,
"blog-post": BlogPostProvider,
"exhibit": ExhibitProvider,
"event": EventProvider,
"organization": OrganizationProvider,
"flatpage": FlatPageProvider,
"user": UserProvider,
"tag": TagProvider,
"term": TermProvider,
"timetable": TimetableProvider,
"comment": CommentProvider,
"like": LikeProvider,
"course": CourseProvider,
}
)
providers: Dict[
str, BaseProvider
] = { # k = request type (param passed in url), v = provider class
"announcement": AnnouncementProvider,
"blog-post": BlogPostProvider,
"exhibit": ExhibitProvider,
"event": EventProvider,
"organization": OrganizationProvider,
"flatpage": FlatPageProvider,
"user": UserProvider,
"tag": TagProvider,
"term": TermProvider,
"timetable": TimetableProvider,
"comment": CommentProvider,
"like": LikeProvider,
"course": CourseProvider,
}

provider_keys = providers.keys()

Expand Down Expand Up @@ -113,7 +127,7 @@ def get_providers_by_operation(
return [
(prov if return_provider else key)
for key, prov in providers.items()
if getattr(prov, f"allow_{operation}", True) == True
if getattr(prov, f"allow_{operation}", True)
]


Expand Down
40 changes: 28 additions & 12 deletions core/api/v3/objects/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
from .announcement import *
from .blog_post import *
from .courses import *
from .event import *
from .exhibit import *
from .flatpage import *
from .organization import *
from .post_interactions import *
from .tag import *
from .term import *
from .timetable import *
from .user import *
from .announcement import AnnouncementProvider
from .blog_post import BlogPostProvider
from .courses import CourseProvider
from .event import EventProvider
from .exhibit import ExhibitProvider
from .flatpage import FlatPageProvider
from .organization import OrganizationProvider
from .post_interactions import CommentProvider, LikeProvider
from .tag import TagProvider
from .term import TermProvider
from .timetable import TimetableProvider
from .user import UserProvider

__all__ = [
"AnnouncementProvider",
"BlogPostProvider",
"CourseProvider",
"EventProvider",
"ExhibitProvider",
"OrganizationProvider",
"TagProvider",
"TermProvider",
"TimetableProvider",
"UserProvider",
"CommentProvider",
"LikeProvider",
"FlatPageProvider",
]
4 changes: 2 additions & 2 deletions core/api/v3/objects/announcement.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
SupervisorField,
TagRelatedField,
)
from core.api.utils import ModelAbilityField
from core.api.utils.last_modified import ModelAbilityField
from core.models import Announcement, User
from core.utils.mail import send_mail

Expand Down Expand Up @@ -54,7 +54,7 @@ def save(self, **kwargs):
if obj.status not in ("d", "p"):
notify_supervisors = True
if obj.status != "a":
obj.message = f"Successfully sent announcement for review."
obj.message = "Successfully sent announcement for review."
obj.status = "p" if obj.status != "d" else "d"

if notify_supervisors:
Expand Down
4 changes: 1 addition & 3 deletions core/api/v3/objects/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@


class BaseProvider(ABC, object):
allow_list: bool = (
True # Is the view able to list the model's objects. (e.g. /user would list all users
)
allow_list: bool = True # Is the view able to list the model's objects. (e.g. /user would list all users
allow_new: bool = True # Is the provider able to create a new object.
kind: APIObjOperations # type of view
listing_filters_ignore: List[str] = []
Expand Down
Loading

0 comments on commit d6ded90

Please sign in to comment.