Skip to content

Commit

Permalink
Merge branch 'master' into club-diff
Browse files Browse the repository at this point in the history
  • Loading branch information
Porcupine1 committed Dec 24, 2024
2 parents 0508c8b + 56b9394 commit 327ccf7
Show file tree
Hide file tree
Showing 97 changed files with 3,118 additions and 1,234 deletions.
16 changes: 4 additions & 12 deletions .github/workflows/build-and-deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,6 @@ jobs:
black: false
ruff: true

frontend-check:
name: "Frontend Check"
uses: pennlabs/shared-actions/.github/workflows/react-check.yaml@v0.1
with:
path: frontend
nodeVersion: 20.11.1

build-backend:
name: Build backend
runs-on: ubuntu-latest
Expand All @@ -47,7 +40,7 @@ jobs:
cache-to: type=local,dest=/tmp/.buildx-cache
tags: pennlabs/penn-clubs-backend:latest,pennlabs/penn-clubs-backend:${{ github.sha }}
outputs: type=docker,dest=/tmp/image.tar
- uses: actions/upload-artifact@v2
- uses: actions/upload-artifact@v4
with:
name: build-backend
path: /tmp/image.tar
Expand Down Expand Up @@ -75,20 +68,19 @@ jobs:
cache-to: type=local,dest=/tmp/.buildx-cache
tags: pennlabs/penn-clubs-frontend:latest,pennlabs/penn-clubs-frontend:${{ github.sha }}
outputs: type=docker,dest=/tmp/image.tar
- uses: actions/upload-artifact@v2
- uses: actions/upload-artifact@v4
with:
name: build-frontend
path: /tmp/image.tar
needs: frontend-check

publish:
name: Publish Images
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/master'
steps:
- uses: actions/checkout@v2
- uses: actions/download-artifact@v2
- uses: geekyeggo/delete-artifact@v1
- uses: actions/download-artifact@v4
- uses: geekyeggo/delete-artifact@v5
with:
name: |-
build-backend
Expand Down
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
# Penn Clubs

[![Build and Deploy](https://github.com/pennlabs/penn-clubs/workflows/Build%20and%20Deploy/badge.svg)](https://github.com/pennlabs/penn-clubs/actions)
[![Build and Deploy Clubs](https://github.com/pennlabs/penn-clubs/workflows/Build%20and%20Deploy%20Clubs/badge.svg)](https://github.com/pennlabs/penn-clubs/actions)
[![Coverage Status](https://codecov.io/gh/pennlabs/penn-clubs/branch/master/graph/badge.svg)](https://codecov.io/gh/pennlabs/penn-clubs)

Official platform for club discovery, recruitment, and events at Penn.
React/Next.js frontend and Django-based REST API.

## Installation

You will need to start both the backend and the frontend to do Penn Clubs development.

You will need to start both the backend and the frontend to develop on Penn Clubs. Clubs supports Mac and Linux/WSL development.

Questions? Check out our [extended guide](https://github.com/pennlabs/penn-clubs/wiki/Development-Guide) for FAQs.
Expand Down Expand Up @@ -95,4 +93,4 @@ To test ticketing locally, you will need to [install](https://github.com/FiloSot
- `$ mkcert localhost 127.0.0.1 ::1`
- `$ export DOMAIN=https://localhost:3001 NODE_TLS_REJECT_UNAUTHORIZED=0`

Then, after the frontend is running, run `yarn ssl-proxy` **in a new terminal window** and access the application at [https://localhost:3001](https://localhost:3001).
Then, after the frontend is running, run `yarn ssl-proxy` **in a new terminal window** and access the application at [https://localhost:3001](https://localhost:3001).
35 changes: 18 additions & 17 deletions backend/Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion backend/clubs/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
Cart,
Club,
ClubApplication,
ClubApprovalResponseTemplate,
ClubFair,
ClubFairBooth,
ClubFairRegistration,
Expand Down Expand Up @@ -324,7 +325,7 @@ def club(self, obj):

class AdvisorAdmin(admin.ModelAdmin):
search_fields = ("name", "title", "email", "phone", "club__name")
list_display = ("name", "title", "email", "phone", "club", "public")
list_display = ("name", "title", "email", "phone", "club", "visibility")

def club(self, obj):
return obj.club.name
Expand Down Expand Up @@ -415,6 +416,10 @@ class ApplicationSubmissionAdmin(admin.ModelAdmin):
list_display = ("user", "id", "created_at", "status")


class ClubApprovalResponseTemplateAdmin(admin.ModelAdmin):
search_fields = ("title", "content")


admin.site.register(Asset)
admin.site.register(ApplicationCommittee)
admin.site.register(ApplicationExtension)
Expand Down Expand Up @@ -460,3 +465,4 @@ class ApplicationSubmissionAdmin(admin.ModelAdmin):
admin.site.register(TicketTransferRecord)
admin.site.register(Cart)
admin.site.register(ApplicationCycle)
admin.site.register(ClubApprovalResponseTemplate, ClubApprovalResponseTemplateAdmin)
2 changes: 1 addition & 1 deletion backend/clubs/management/commands/daily_notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def send_approval_queue_reminder(self):
group_name = "Approvers"

# only send notifications if it is currently a weekday
if now.isoweekday() not in range(1, 6):
if now.isoweekday() not in range(1, 6) or not settings.REAPPROVAL_QUEUE_OPEN:
return False

# get users in group to send notification to
Expand Down
35 changes: 22 additions & 13 deletions backend/clubs/management/commands/deactivate.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import sys

from django.core.cache import cache
from django.core.management.base import BaseCommand, CommandError
from django.db import transaction

from clubs.models import Club

Expand Down Expand Up @@ -74,21 +76,28 @@ def handle(self, *args, **kwargs):

# deactivate all clubs
if deactivate_clubs:
clubs.update(active=False, approved=None, approved_by=None)

# allow existing approved version to stay on penn clubs website for now
ghosted = 0
for club in clubs:
if club.history.filter(approved=True).exists():
club.ghost = True
club._change_reason = (
"Mark pending approval (yearly renewal process)"
)
club.save(update_fields=["ghost"])
ghosted += 1
num_ghosted = 0

with transaction.atomic():
for club in clubs:
club.active = False
club.approved = None
club.approved_by = None

# allow existing approved version to stay on website for now
if club.history.filter(approved=True).exists():
club.ghost = True
club._change_reason = (
"Mark pending approval (yearly renewal process)"
)
num_ghosted += 1

club.save()
cache.delete(f"clubs:{club.id}-authed") # clear cache
cache.delete(f"clubs:{club.id}-anon")

self.stdout.write(
f"{clubs.count()} clubs deactivated! {ghosted} clubs ghosted!"
f"{clubs.count()} clubs deactivated! {num_ghosted} clubs ghosted!"
)

# send out renewal emails to all clubs
Expand Down
1 change: 0 additions & 1 deletion backend/clubs/management/commands/graduate_users.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ class Command(BaseCommand):
"Mark all memberships where the student has graduated as inactive. "
"This script should be run at the beginning of each year."
)
web_execute = True

def handle(self, *args, **kwargs):
now = timezone.now()
Expand Down
36 changes: 36 additions & 0 deletions backend/clubs/management/commands/osa_perms_updates.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
from django.core.management.base import BaseCommand

from clubs.models import Club


class Command(BaseCommand):
help = "Give superuser to hard-coded user accounts affiliated with OSA."
web_execute = True

def handle(self, *args, **kwargs):
User = get_user_model()
content_type = ContentType.objects.get_for_model(Club)
approve_perm = Permission.objects.get(
codename="approve_club", content_type=content_type
)
pending_perm = Permission.objects.get(
codename="see_pending_clubs", content_type=content_type
)
if not settings.OSA_KEYS:
raise ValueError("OSA_KEYS not set in settings")
if not (approvers := Group.objects.filter(name="Approvers").first()):
raise ValueError("Approvers group not found")
for key in settings.OSA_KEYS:
if not key or not (user := User.objects.get(username=key)):
continue
user.is_superuser = True
user.is_staff = True
user.user_permissions.add(approve_perm)
user.user_permissions.add(pending_perm)
approvers.user_set.add(user)
user.save()
approvers.save()
2 changes: 1 addition & 1 deletion backend/clubs/management/commands/populate.py
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ def get_image(url):
department="Accounting Department",
email="example@example.com",
phone="+12158985000",
defaults={"public": True},
defaults={"visibility": Advisor.ADVISOR_VISIBILITY_STUDENTS},
)

club.tags.add(tag_undergrad)
Expand Down
9 changes: 6 additions & 3 deletions backend/clubs/management/commands/rank.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import datetime
import random
from math import floor

import bleach
import numpy as np
from django.core.management.base import BaseCommand
from django.utils import timezone

Expand Down Expand Up @@ -220,8 +220,11 @@ def rank(self):
if num_testimonials >= 3:
ranking += 5

# rng
ranking += random.random() * 10
# random number, mostly shuffles similar clubs with average of 25 points
# but with long right tail to periodically feature less popular clubs
# given ~700 active clubs, multiplier c, expected # clubs with rand > cd
# is 257, 95, 35, 13, 5, 2, 1 for c = 1, 2, 3, 4, 5, 6, 7
ranking += np.random.standard_exponential() * 25

club.rank = floor(ranking)
club.skip_history_when_saving = True
Expand Down
4 changes: 3 additions & 1 deletion backend/clubs/management/commands/send_emails.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ def add_arguments(self, parser):
"hap_intro_remind",
"hap_second_round",
"hap_partner_communication",
"revised_fair_date",
"wc_intro",
"osa_email_communication",
"ics_calendar_ingestation",
Expand Down Expand Up @@ -452,6 +453,7 @@ def handle(self, *args, **kwargs):
"admin_outreach",
"semesterly_email",
"update_officers",
"revised_fair_date",
}:
clubs = Club.objects.all()
attachment = None
Expand All @@ -473,7 +475,7 @@ def handle(self, *args, **kwargs):
for club in clubs:
if action == "semesterly_email":
context = {"code": club.code}
elif action == "update_officers":
elif action == "update_officers" or action == "revised_fair_date":
context = {
"name": club.name,
"url": f"https://pennclubs.com/club/{club.code}/edit/member",
Expand Down
18 changes: 18 additions & 0 deletions backend/clubs/migrations/0112_clubfair_virtual.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.0.4 on 2024-08-21 18:21

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("clubs", "0111_alter_club_rank_alter_historicalclub_rank"),
]

operations = [
migrations.AddField(
model_name="clubfair",
name="virtual",
field=models.BooleanField(default=False),
),
]
18 changes: 18 additions & 0 deletions backend/clubs/migrations/0113_badge_message.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.0.4 on 2024-08-30 20:47

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("clubs", "0112_clubfair_virtual"),
]

operations = [
migrations.AddField(
model_name="badge",
name="message",
field=models.TextField(blank=True, null=True),
),
]
Loading

0 comments on commit 327ccf7

Please sign in to comment.