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

replace dev tools with better dev tools #486

Open
wants to merge 29 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
2bd7179
add mise.toml file that includes poetry
cameronbrill May 3, 2024
f954b20
fix typo
cameronbrill May 3, 2024
173f634
add tool for installing poetry deps
cameronbrill May 3, 2024
bd4690c
fix poetry install
cameronbrill May 3, 2024
7a443d0
mise install in setup
cameronbrill May 3, 2024
f09c104
update GHAs
cameronbrill May 3, 2024
2053f98
install ruff and isolate dev dependencies in the modern way
cameronbrill May 3, 2024
2326e9a
run ruff and fix initial errors
cameronbrill May 3, 2024
27fb039
replace black/isort and format code with ruff
cameronbrill May 3, 2024
124c716
enable all of E rules
cameronbrill May 3, 2024
3b424fd
enable a bunch of rules
cameronbrill May 3, 2024
4b79cc9
enable pyupgrade ruleset and fix
cameronbrill May 3, 2024
dae3278
enable/disable some more rules
cameronbrill May 3, 2024
426f7a5
enable security rule and fix stuff
cameronbrill May 3, 2024
05c9d5d
ENABLE ALL THE RULES
cameronbrill May 3, 2024
c45c201
update my email
cameronbrill May 3, 2024
ffb8f51
i removed the hooks
cameronbrill May 3, 2024
d5eb5a3
ignore conflicting rule
cameronbrill May 3, 2024
ecd5d52
setup new pre-commit hooks
cameronbrill May 3, 2024
0523802
make sure all requisite files are initialized before installation
cameronbrill May 3, 2024
ba03392
add dependency focused pre-commit hooks
cameronbrill May 3, 2024
966ff1a
update lockfile
cameronbrill May 3, 2024
1477b7d
initialize mise with experimental mode
cameronbrill May 3, 2024
a2afb0a
fix the stuff
cameronbrill May 3, 2024
ee2c0f1
fix stuff
cameronbrill May 3, 2024
39d5884
pin poetry version
cameronbrill May 3, 2024
b13f3bd
fix
cameronbrill May 3, 2024
aea87e1
make hooks less annoying
cameronbrill May 3, 2024
fc2b2c9
FIX
cameronbrill May 3, 2024
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
2 changes: 1 addition & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: actions/checkout@v4
- name: Login to Heroku Container registry
env:
HEROKU_API_KEY: ${{ secrets.HEROKU_API_KEY }}
Expand Down
59 changes: 28 additions & 31 deletions .github/workflows/quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,42 @@ name: Code Quality Checks
on: [push]

jobs:
black:
name: 'Check code quality with black'
format:
name: 'Format code'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: 'Set up Python 3.7'
uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Install dependencies
- uses: actions/checkout@v4
- name: Setup environment
run: |
python -m pip install --upgrade pip
python -m pip install black
- name: Check formatting
./setup.bash
echo "$HOME/.local/share/mise/bin" >> $GITHUB_PATH
echo "$HOME/.local/share/mise/shims" >> $GITHUB_PATH

- name: Install python dependencies
run: |
poetry install --with dev
source $(poetry env info --path)/bin/activate
- name: Format
run: |
cd hiss
black . --check --exclude=".*/migrations,env"
flake:
name: 'Check code health with Flake8'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: cclauss/[email protected]
with:
args: "flake8 . --exclude=\"env,**/migrations,__init__.py,hiss/hiss/settings/**\" --max-line-length=120"
pylint:
name: 'Check code quality with pylint'
mise run format --check

lint:
name: 'Run python linter (ruff)'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: 'Set up Python 3.7'
uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Install dependencies
- uses: actions/checkout@v4
- name: Setup environment
run: |
./setup.bash
echo "$HOME/.local/share/mise/bin" >> $GITHUB_PATH
echo "$HOME/.local/share/mise/shims" >> $GITHUB_PATH

- name: Install python dependencies
run: |
python -m pip install --upgrade pip
python -m pip install -r hiss/requirements.txt
poetry install --with dev
source $(poetry env info --path)/bin/activate
- name: Lint
run: |
cd hiss
pylint --exit-zero --rcfile=.pylintrc application rsvp shared status user volunteer
mise run lint --no-fix
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ jobs:
name: 'Run unit tests'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Build the stack
run: docker-compose run web python3 manage.py test
coverage:
name: 'Check test coverage'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Build the stack
run: docker-compose build
- name: Create coverage XML report
Expand Down
22 changes: 22 additions & 0 deletions .mise.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[tools]
poetry = {version='1.8.2', pyproject='pyproject.toml'}
python = "3.8.19"
lefthook = "latest"

[plugins]
poetry="https://github.com/mise-plugins/mise-poetry.git"

[tasks.lint]
alias = "l"
run = "ruff check . --force-exclude --preview --config ./pyproject.toml"

[tasks.format]
alias = "f"
run = "ruff format . --force-exclude --preview --config ./pyproject.toml"

[tasks.pre-commit]
depends = ["lint", "format"]
hide = true

[settings]
experimental = true
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ If you have questions, we might've answered them already on the [wiki](https://g

### Local Development

#### First time here?

You should run `./setup.bash` to set up your local environment. This will ensure you have the correct versions of all tools now and as they're updated.

#### Everyone else

For local development, we highly encourage using [Docker Compose](https://docs.docker.com/compose/).

After Docker Compose is installed, there are just a few steps left for first-time setup:
Expand Down Expand Up @@ -71,12 +77,16 @@ python3 manage.py migrate --run-syncdb

# Contributing

Install [Poetry](https://python-poetry.org/docs/#installation). Once installed, navigate to the root of the project and run the following:
From the root of the project and run the following:
```
./setup.bash
```
After that script has set up your environment, run:
```
poetry install
poetry run autohooks activate
```
This enables pre-commit hooks to make sure your code is formatted prooperly, so you won't get blocked in a PR.

Now you're good to go!


# Brought to you by
Expand Down
66 changes: 23 additions & 43 deletions hiss/application/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import csv
from typing import List, Tuple

from address.forms import AddressWidget
from address.models import AddressField
from django import forms
from django.conf import settings
from django.contrib import admin
Expand All @@ -27,14 +29,11 @@
)
from shared.admin_functions import send_mass_html_mail

from address.forms import AddressWidget
from address.models import AddressField


class ApplicationAdminForm(forms.ModelForm):
class Meta:
model = Application
fields = "__all__"
fields = "__all__" # noqa: DJ007
widgets = {
"gender": forms.RadioSelect,
"classification": forms.RadioSelect,
Expand All @@ -46,11 +45,10 @@ class Meta:
def build_approval_email(
application: Application, confirmation_deadline: timezone.datetime
) -> Tuple[str, str, str, None, List[str]]:
"""
Creates a datatuple of (subject, message, html_message, from_email, [to_email]) indicating that a `User`'s
application has been approved.
"""
subject = f"ACTION REQUIRED: One last step for your {settings.EVENT_NAME} application!"
"""Create a datatuple of (subject, message, html_message, from_email, [to_email]) indicating that a `User`'s application has been approved."""
subject = (
f"ACTION REQUIRED: One last step for your {settings.EVENT_NAME} application!"
)

context = {
"first_name": application.first_name,
Expand All @@ -66,10 +64,7 @@ def build_approval_email(


def build_rejection_email(application: Application) -> Tuple[str, str, None, List[str]]:
"""
Creates a datatuple of (subject, message, html_message, from_email, [to_email]) indicating that a `User`'s
application has been rejected.
"""
"""Create a datatuple of (subject, message, html_message, from_email, [to_email]) indicating that a `User`'s application has been rejected."""
subject = f"Regarding your {settings.EVENT_NAME} application"

context = {
Expand All @@ -85,8 +80,9 @@ def build_rejection_email(application: Application) -> Tuple[str, str, None, Lis


def approve(_modeladmin, _request: HttpRequest, queryset: QuerySet) -> None:
"""
Sets the value of the `approved` field for the selected `Application`s to `True`, creates an RSVP deadline for
"""Manually approve a registration application.

Set the value of the `approved` field for the selected `Application`s to `True`, creates an RSVP deadline for
each user based on how many days each wave gives to RSVP, and then emails all of the users to inform them that
their applications have been approved.
"""
Expand All @@ -106,9 +102,7 @@ def approve(_modeladmin, _request: HttpRequest, queryset: QuerySet) -> None:


def reject(_modeladmin, _request: HttpRequest, queryset: QuerySet) -> None:
"""
Sets the value of the `approved` field for the selected `Application`s to `False`
"""
"""Set the value of the `approved` field for the selected `Application`s to `False`."""
email_tuples = []
with transaction.atomic():
for application in queryset:
Expand All @@ -119,35 +113,21 @@ def reject(_modeladmin, _request: HttpRequest, queryset: QuerySet) -> None:


def resend_confirmation(_modeladmin, _request: HttpRequest, queryset: QuerySet) -> None:
"""
Resends the confirmation email to the selected applications.
"""
"""Resends the confirmation email to the selected applications."""
for application in queryset:
send_confirmation_email(application)


def export_application_emails(_modeladmin, _request: HttpRequest, queryset: QuerySet):
"""
Exports the emails related to the selected `Application`s to a CSV file
"""
"""Export the emails related to the selected `Application`s to a CSV file."""
response = HttpResponse(content_type="text/csv")
response["Content-Disposition"] = 'attachment; filename="emails.csv"'

writer = csv.writer(response)
writer.writerow(
[
"email",
"shirt_size"
]
)
writer.writerow(["email", "shirt_size"])
for instance in queryset:
instance: Application = instance
writer.writerow(
[
instance.user.email,
instance.shirt_size
]
)
instance: Application = instance # noqa: PLW2901, PLW0127
writer.writerow([instance.user.email, instance.shirt_size])

return response

Expand All @@ -166,10 +146,10 @@ class RaceFilter(admin.SimpleListFilter):
title = "Race"
parameter_name = "race"

def lookups(self, request: HttpRequest, model_admin) -> List[Tuple[str, str]]:
def lookups(self, _request: HttpRequest, _model_admin) -> List[Tuple[str, str]]:
return RACES

def queryset(self, request: HttpRequest, queryset: QuerySet):
def queryset(self, _request: HttpRequest, queryset: QuerySet):
if self.value():
return queryset.filter(race__contains=self.value())
return queryset
Expand Down Expand Up @@ -206,8 +186,8 @@ class ApplicationAdmin(admin.ModelAdmin):
("grad_year", ChoiceDropdownFilter),
("num_hackathons_attended", ChoiceDropdownFilter),
("wares", ChoiceDropdownFilter),
# ("technology_experience", ChoiceDropdownFilter),
# ("dietary_restrictions", ChoiceDropdownFilter),
# ("technology_experience", ChoiceDropdownFilter), # noqa: ERA001
# ("dietary_restrictions", ChoiceDropdownFilter), # noqa: ERA001
("shirt_size", ChoiceDropdownFilter),
("datetime_submitted", DateRangeFilter),
RaceFilter,
Expand Down Expand Up @@ -297,10 +277,10 @@ class ApplicationAdmin(admin.ModelAdmin):

actions = [approve, reject, export_application_emails, resend_confirmation]

def has_add_permission(self, request):
def has_add_permission(self, _request):
return True

def has_change_permission(self, request, obj=None):
def has_change_permission(self, _request, _obj=None):
return True

@staticmethod
Expand Down
10 changes: 6 additions & 4 deletions hiss/application/apple_wallet.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os

import bcrypt
import os
from django.conf import settings


Expand All @@ -9,7 +9,9 @@ def get_apple_wallet_pass_url(email: str) -> str:
salt = os.environ.get("APPLE_WALLET_SALT").encode()
hashed_email = bcrypt.hashpw(email, salt)

#Make hash alphanumeric so that it can be used as a filename
alphanumeric_hash = ''.join(char for char in hashed_email.decode() if char.isalnum())

# Make hash alphanumeric so that it can be used as a filename
alphanumeric_hash = "".join(
char for char in hashed_email.decode() if char.isalnum()
)

return settings.APPLE_WALLET_S3_BUCKET_URL + "/" + alphanumeric_hash + ".pkpass"
30 changes: 14 additions & 16 deletions hiss/application/emails.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
from django.template.loader import render_to_string
from django.utils import html

from application.models import Application
from application.apple_wallet import get_apple_wallet_pass_url
from application.models import Application


def send_creation_email(app: Application) -> None:
"""
Sends an email to the user informing them of their newly-created app.
"""Send an email to the user informing them of their newly-created app.

:param app: The user's newly-created application
:return: None
:return: None.
"""
subject = f"We've received your application for {settings.EVENT_NAME}!"
template_name = "application/emails/created.html"
Expand All @@ -31,13 +31,13 @@ def send_creation_email(app: Application) -> None:


def send_confirmation_email(app: Application) -> None:
"""
Sends a confirmation email to a user, which contains their QR code as well as additional event information.
"""Send a confirmation email to a user, which contains their QR code as well as additional event information.

:param app: The user's application
:type app: Application
:return: None
:return: None.
"""
subject = f"TAMUhack Waitlist: Important Day-Of Information"
subject = "TAMUhack Waitlist: Important Day-Of Information"
email_template = "application/emails/confirmed.html"
context = {
"first_name": app.first_name,
Expand All @@ -54,14 +54,12 @@ def send_confirmation_email(app: Application) -> None:
)
email.attach_alternative(html_msg, "text/html")

qr_content = json.dumps(
{
"first_name": app.first_name,
"last_name": app.last_name,
"email": app.user.email,
"university": app.school.name,
}
)
qr_content = json.dumps({
"first_name": app.first_name,
"last_name": app.last_name,
"email": app.user.email,
"university": app.school.name,
})
qr_code = pyqrcode.create(qr_content)
qr_stream = BytesIO()
qr_code.png(qr_stream, scale=5)
Expand Down
Loading
Loading