style: reformat

This commit is contained in:
Ethan Nguyen 2021-04-19 18:50:03 -04:00
parent 9ad55a731d
commit 337d3e2f35
No known key found for this signature in database
GPG Key ID: B4CA5339AF911920
31 changed files with 671 additions and 223 deletions

35
scripts/format.sh Executable file
View File

@ -0,0 +1,35 @@
#!/bin/bash
# MIT License
#
# Copyright (c) 2017 The TJ Director Development Team
# Copyright (c) 2019 The TJHSST Director 4.0 Development Team & Contributors
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
cd "$(dirname -- "$(dirname -- "$(readlink -f "$0")")")"
for cmd in black autopep8 isort; do
if [[ ! -x "$(which "$cmd")" ]]; then
echo "Could not find $cmd. Please make sure that black, autopep8, and isort are all installed."
exit 1
fi
done
black tjdests && autopep8 --in-place --recursive tjdests && isort tjdests

View File

@ -1,47 +1,69 @@
from django import forms
from django.contrib.auth import password_validation
from crispy_forms.helper import FormHelper from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit from crispy_forms.layout import Submit
from django import forms
from django.contrib.auth import password_validation
class TOSForm(forms.Form): class TOSForm(forms.Form):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.helper = FormHelper() self.helper = FormHelper()
self.helper.form_method = 'post' self.helper.form_method = "post"
self.helper.add_input(Submit('submit', 'Submit')) self.helper.add_input(Submit("submit", "Submit"))
accept_tos = forms.BooleanField(required=True, label="I accept the terms of the GNU Affero General Public License as displayed above," accept_tos = forms.BooleanField(
" and I understand that the terms that provide this software WITHOUT ANY WARRANTY;" required=True,
" without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.") label="I accept the terms of the GNU Affero General Public License as displayed above,"
" and I understand that the terms that provide this software WITHOUT ANY WARRANTY;"
" without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.",
)
password = forms.CharField(widget=forms.PasswordInput, required=True) password = forms.CharField(widget=forms.PasswordInput, required=True)
password_confirm = forms.CharField(widget=forms.PasswordInput, required=True) password_confirm = forms.CharField(
widget=forms.PasswordInput, required=True)
understand_no_reset = forms.BooleanField(required=True, label="I understand that there is NO PASSWORD RESET functionality once I no longer have access to Ion.") understand_no_reset = forms.BooleanField(
required=True,
label="I understand that there is NO PASSWORD RESET functionality once I no longer have access to Ion.",
)
def clean(self): def clean(self):
cleaned_data = super(TOSForm, self).clean() cleaned_data = super(TOSForm, self).clean()
password1 = cleaned_data.get('password') password1 = cleaned_data.get("password")
password2 = cleaned_data.get('password_confirm') password2 = cleaned_data.get("password_confirm")
if password1 and password1 != password2: if password1 and password1 != password2:
raise forms.ValidationError({"password": ["The two passwords do not match.",]}) raise forms.ValidationError(
{
"password": [
"The two passwords do not match.",
]
}
)
# Validate checkboxes checked # Validate checkboxes checked
accept_tos = cleaned_data.get("accept_tos") accept_tos = cleaned_data.get("accept_tos")
understand_no_reset = cleaned_data.get("understand_no_reset") understand_no_reset = cleaned_data.get("understand_no_reset")
if not accept_tos: if not accept_tos:
raise forms.ValidationError({"accept_tos": ["You must accept the license terms to continue.",]}) raise forms.ValidationError(
{
"accept_tos": [
"You must accept the license terms to continue.",
]
}
)
if not understand_no_reset: if not understand_no_reset:
raise forms.ValidationError({"understand_no_reset": ["You must acknowledge that there is no password reset to continue.",]}) raise forms.ValidationError(
{
"understand_no_reset": [
"You must acknowledge that there is no password reset to continue.",
]
}
)
# Validate the password for complexity, etc. # Validate the password for complexity, etc.
validators = password_validation.get_default_password_validators() validators = password_validation.get_default_password_validators()
password_validation.validate_password(password1, None, validators) password_validation.validate_password(password1, None, validators)

View File

@ -2,45 +2,117 @@
import django.contrib.auth.models import django.contrib.auth.models
import django.contrib.auth.validators import django.contrib.auth.validators
from django.db import migrations, models
import django.utils.timezone import django.utils.timezone
from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = []
]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='User', name="User",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('password', models.CharField(max_length=128, verbose_name='password')), "id",
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), models.BigAutoField(
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), auto_created=True,
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), primary_key=True,
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), serialize=False,
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), verbose_name="ID",
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), ),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), ),
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), ("password", models.CharField(
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), max_length=128, verbose_name="password")),
('accepted_terms', models.BooleanField(default=False)), (
('graduation_year', models.PositiveSmallIntegerField(null=True)), "last_login",
('is_senior', models.BooleanField(default=False)), models.DateTimeField(
('publish_data', models.BooleanField(default=False, verbose_name='Publish my data')), blank=True, null=True, verbose_name="last login"
('biography', models.TextField(blank=True)), ),
),
(
"is_superuser",
models.BooleanField(
default=False,
help_text="Designates that this user has all permissions without explicitly assigning them.",
verbose_name="superuser status",
),
),
(
"username",
models.CharField(
error_messages={
"unique": "A user with that username already exists."
},
help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
max_length=150,
unique=True,
validators=[
django.contrib.auth.validators.UnicodeUsernameValidator()
],
verbose_name="username",
),
),
(
"first_name",
models.CharField(
blank=True, max_length=150, verbose_name="first name"
),
),
(
"last_name",
models.CharField(
blank=True, max_length=150, verbose_name="last name"
),
),
(
"email",
models.EmailField(
blank=True, max_length=254, verbose_name="email address"
),
),
(
"is_staff",
models.BooleanField(
default=False,
help_text="Designates whether the user can log into this admin site.",
verbose_name="staff status",
),
),
(
"is_active",
models.BooleanField(
default=True,
help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",
verbose_name="active",
),
),
(
"date_joined",
models.DateTimeField(
default=django.utils.timezone.now, verbose_name="date joined"
),
),
("accepted_terms", models.BooleanField(default=False)),
("graduation_year", models.PositiveSmallIntegerField(null=True)),
("is_senior", models.BooleanField(default=False)),
(
"publish_data",
models.BooleanField(
default=False, verbose_name="Publish my data"),
),
("biography", models.TextField(blank=True)),
], ],
options={ options={
'verbose_name': 'user', "verbose_name": "user",
'verbose_name_plural': 'users', "verbose_name_plural": "users",
'abstract': False, "abstract": False,
}, },
managers=[ managers=[
('objects', django.contrib.auth.models.UserManager()), ("objects", django.contrib.auth.models.UserManager()),
], ],
), ),
] ]

View File

@ -1,7 +1,7 @@
# Generated by Django 3.2 on 2021-04-19 15:03 # Generated by Django 3.2 on 2021-04-19 15:03
from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
@ -9,25 +9,46 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
('auth', '0012_alter_user_first_name_max_length'), ("auth", "0012_alter_user_first_name_max_length"),
('authentication', '0001_initial'), ("authentication", "0001_initial"),
('destinations', '0001_initial'), ("destinations", "0001_initial"),
] ]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='user', model_name="user",
name='attending_decision', name="attending_decision",
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='attending_college', to='destinations.decision', verbose_name='College attending'), field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="attending_college",
to="destinations.decision",
verbose_name="College attending",
),
), ),
migrations.AddField( migrations.AddField(
model_name='user', model_name="user",
name='groups', name="groups",
field=models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups'), field=models.ManyToManyField(
blank=True,
help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.",
related_name="user_set",
related_query_name="user",
to="auth.Group",
verbose_name="groups",
),
), ),
migrations.AddField( migrations.AddField(
model_name='user', model_name="user",
name='user_permissions', name="user_permissions",
field=models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions'), field=models.ManyToManyField(
blank=True,
help_text="Specific permissions for this user.",
related_name="user_set",
related_query_name="user",
to="auth.Permission",
verbose_name="user permissions",
),
), ),
] ]

View File

@ -6,13 +6,17 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('authentication', '0002_initial'), ("authentication", "0002_initial"),
] ]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='user', model_name="user",
name='publish_data', name="publish_data",
field=models.BooleanField(default=False, help_text='Unless this is set, your data will not appear publicly.', verbose_name='Publish my data'), field=models.BooleanField(
default=False,
help_text="Unless this is set, your data will not appear publicly.",
verbose_name="Publish my data",
),
), ),
] ]

View File

@ -1,25 +1,33 @@
# Generated by Django 3.2 on 2021-04-19 17:13 # Generated by Django 3.2 on 2021-04-19 17:13
from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('destinations', '0005_alter_decision_admission_status'), ("destinations", "0005_alter_decision_admission_status"),
('authentication', '0003_alter_user_publish_data'), ("authentication", "0003_alter_user_publish_data"),
] ]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='user', model_name="user",
name='is_student', name="is_student",
field=models.BooleanField(default=False), field=models.BooleanField(default=False),
), ),
migrations.AlterField( migrations.AlterField(
model_name='user', model_name="user",
name='attending_decision', name="attending_decision",
field=models.ForeignKey(blank=True, help_text="Can't see your college? Make sure you've added a decision with an admit status.", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='attending_college', to='destinations.decision', verbose_name='College attending'), field=models.ForeignKey(
blank=True,
help_text="Can't see your college? Make sure you've added a decision with an admit status.",
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="attending_college",
to="destinations.decision",
verbose_name="College attending",
),
), ),
] ]

View File

@ -1,8 +1,9 @@
from django.db import models
from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import AbstractUser
from django.db import models
from ..destinations.models import Decision, TestScore from ..destinations.models import Decision, TestScore
class User(AbstractUser): class User(AbstractUser):
accepted_terms = models.BooleanField(default=False) accepted_terms = models.BooleanField(default=False)
graduation_year = models.PositiveSmallIntegerField(null=True) graduation_year = models.PositiveSmallIntegerField(null=True)
@ -11,12 +12,22 @@ class User(AbstractUser):
is_student = models.BooleanField(default=False) is_student = models.BooleanField(default=False)
# The rest are used only if a senior # The rest are used only if a senior
publish_data = models.BooleanField(default=False, verbose_name="Publish my data", help_text="Unless this is set, your data will not appear publicly.") publish_data = models.BooleanField(
default=False,
verbose_name="Publish my data",
help_text="Unless this is set, your data will not appear publicly.",
)
biography = models.TextField(blank=True) biography = models.TextField(blank=True)
attending_decision = models.ForeignKey(Decision, on_delete=models.SET_NULL, null=True, blank=True, attending_decision = models.ForeignKey(
verbose_name="College attending", related_name="attending_college", Decision,
help_text="Can't see your college? Make sure you've added a decision with an admit status.") on_delete=models.SET_NULL,
null=True,
blank=True,
verbose_name="College attending",
related_name="attending_college",
help_text="Can't see your college? Make sure you've added a decision with an admit status.",
)
def __str__(self): def __str__(self):
return f"{self.first_name} {self.last_name}" return f"{self.first_name} {self.last_name}"

View File

@ -7,14 +7,16 @@ class IonOauth2(BaseOAuth2):
AUTHORIZATION_URL = "https://ion.tjhsst.edu/oauth/authorize" AUTHORIZATION_URL = "https://ion.tjhsst.edu/oauth/authorize"
ACCESS_TOKEN_URL = "https://ion.tjhsst.edu/oauth/token" ACCESS_TOKEN_URL = "https://ion.tjhsst.edu/oauth/token"
ACCESS_TOKEN_METHOD = "POST" ACCESS_TOKEN_METHOD = "POST"
EXTRA_DATA = [("refresh_token", "refresh_token", True), ("expires_in", "expires")] EXTRA_DATA = [("refresh_token", "refresh_token", True),
("expires_in", "expires")]
def get_scope(self): def get_scope(self):
return ["read"] return ["read"]
def get_user_details(self, response): def get_user_details(self, response):
profile = self.get_json( profile = self.get_json(
"https://ion.tjhsst.edu/api/profile", params={"access_token": response["access_token"]} "https://ion.tjhsst.edu/api/profile",
params={"access_token": response["access_token"]},
) )
# fields used to populate/update User model # fields used to populate/update User model
@ -31,7 +33,7 @@ class IonOauth2(BaseOAuth2):
"is_student": profile["is_student"], "is_student": profile["is_student"],
"is_teacher": profile["is_teacher"], "is_teacher": profile["is_teacher"],
"graduation_year": profile["graduation_year"], "graduation_year": profile["graduation_year"],
"is_senior": int(profile["graduation_year"]) == settings.SENIOR_GRAD_YEAR "is_senior": int(profile["graduation_year"]) == settings.SENIOR_GRAD_YEAR,
} }
def get_user_id(self, details, response): def get_user_id(self, details, response):

View File

@ -1,5 +1,6 @@
from django.contrib.auth.views import LogoutView from django.contrib.auth.views import LogoutView
from django.urls import path from django.urls import path
from . import views from . import views
app_name = "authentication" app_name = "authentication"

View File

@ -1,9 +1,9 @@
from django.contrib import messages
from django.contrib.auth import login, logout from django.contrib.auth import login, logout
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.contrib.auth.views import LoginView from django.contrib.auth.views import LoginView
from django.contrib import messages
from django.http import HttpRequest, HttpResponse from django.http import HttpRequest, HttpResponse
from django.shortcuts import render, redirect from django.shortcuts import redirect, render
from django.urls import reverse from django.urls import reverse
from tjdests.apps.authentication.decorators import require_accept_tos from tjdests.apps.authentication.decorators import require_accept_tos
@ -13,6 +13,7 @@ from tjdests.apps.authentication.forms import TOSForm
def index_view(request: HttpRequest) -> HttpResponse: def index_view(request: HttpRequest) -> HttpResponse:
return render(request, "authentication/index.html") return render(request, "authentication/index.html")
@login_required @login_required
def accept_tos_view(request: HttpRequest) -> HttpResponse: def accept_tos_view(request: HttpRequest) -> HttpResponse:
assert request.user.is_authenticated assert request.user.is_authenticated
@ -33,7 +34,11 @@ def accept_tos_view(request: HttpRequest) -> HttpResponse:
request.user.set_password(form.cleaned_data.get("password")) request.user.set_password(form.cleaned_data.get("password"))
request.user.save() request.user.save()
login(request, request.user, backend='django.contrib.auth.backends.ModelBackend') login(
request,
request.user,
backend="django.contrib.auth.backends.ModelBackend",
)
messages.success(request, "You have logged in.") messages.success(request, "You have logged in.")
@ -45,6 +50,6 @@ def accept_tos_view(request: HttpRequest) -> HttpResponse:
return render(request, "authentication/accept_tos.html", context=context) return render(request, "authentication/accept_tos.html", context=context)
class LoginViewCustom(LoginView): class LoginViewCustom(LoginView):
template_name = "authentication/login.html" template_name = "authentication/login.html"

View File

@ -1,4 +1,5 @@
from django.conf import settings from django.conf import settings
def settings_renderer(request): def settings_renderer(request):
return {"settings": settings} return {"settings": settings}

View File

@ -1,6 +1,6 @@
from django.contrib import admin from django.contrib import admin
from .models import College, TestScore, Decision from .models import College, Decision, TestScore
admin.site.register(College) admin.site.register(College)
admin.site.register(TestScore) admin.site.register(TestScore)

View File

@ -5,6 +5,7 @@ from django.core.management.base import BaseCommand
from ...models import College from ...models import College
class Command(BaseCommand): class Command(BaseCommand):
help = "Imports a CSV of CEEB codes as colleges" help = "Imports a CSV of CEEB codes as colleges"
@ -20,9 +21,21 @@ class Command(BaseCommand):
reader = csv.DictReader(file) reader = csv.DictReader(file)
for line in reader: for line in reader:
result = College.objects.update_or_create(ceeb_code=line["CEEB"], defaults={"name": line["College Name"], "location": f"{line['City']}, {line['State']}"}) result = College.objects.update_or_create(
ceeb_code=line["CEEB"],
defaults={
"name": line["College Name"],
"location": f"{line['City']}, {line['State']}",
},
)
if result[1]: if result[1]:
self.stdout.write(f"Added university {result[0].name}.", style_func=self.style.SUCCESS) self.stdout.write(
f"Added university {result[0].name}.",
style_func=self.style.SUCCESS,
)
else: else:
self.stdout.write(f"Did not update university {result[0].name}.", style_func=self.style.WARNING) self.stdout.write(
f"Did not update university {result[0].name}.",
style_func=self.style.WARNING,
)

View File

@ -1,8 +1,8 @@
# Generated by Django 3.2 on 2021-04-19 15:03 # Generated by Django 3.2 on 2021-04-19 15:03
import django.db.models.deletion
from django.conf import settings from django.conf import settings
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
@ -15,30 +15,165 @@ class Migration(migrations.Migration):
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='College', name="College",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('ceeb_code', models.PositiveSmallIntegerField(verbose_name='CEEB Code')), "id",
('name', models.CharField(max_length=250)), models.BigAutoField(
('location', models.CharField(max_length=250)), auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"ceeb_code",
models.PositiveSmallIntegerField(verbose_name="CEEB Code"),
),
("name", models.CharField(max_length=250)),
("location", models.CharField(max_length=250)),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
name='TestScore', name="TestScore",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('exam_type', models.CharField(choices=[('ACT_ENGL', 'ACT English (Grammar)'), ('ACT_MATH', 'ACT Math'), ('ACT_READ', 'ACT Reading'), ('ACT_SCI', 'ACT Science'), ('ACT_COMP', 'ACT Composite'), ('SAT_EBRW', 'SAT Verbal'), ('SAT_MATH', 'SAT Math'), ('SAT_TOTAL', 'SAT Total'), ('SAT2_MATH1', 'SAT Subject Test Math 1'), ('SAT2_MATH2', 'SAT Subject Test Math 2'), ('SAT2_BIO', 'SAT Subject Test Biology'), ('SAT2_CHEM', 'SAT Subject Test Chemistry'), ('SAT2_PHYS', 'SAT Subject Test Physics'), ('SAT2_ENGL', 'SAT Subject Test English'), ('SAT2_USH', 'SAT Subject Test U.S. History'), ('SAT2_WH', 'SAT Subject Test World History'), ('SAT2_ES', 'SAT Subject Test Spanish'), ('SAT2_ESL', 'SAT Subject Test Spanish with Listening'), ('SAT2_FR', 'SAT Subject Test French'), ('SAT2_FRL', 'SAT Subject Test French with Listening'), ('SAT2_ZHL', 'SAT Subject Test Chinese with Listening'), ('SAT2_IT', 'SAT Subject Test Italian'), ('SAT2_DE', 'SAT Subject Test German'), ('SAT2_DEL', 'SAT Subject Test German with Listening'), ('SAT2_HE', 'SAT Subject Test Modern Hebrew'), ('SAT2_LA', 'SAT Subject Test Latin'), ('SAT2_JAL', 'SAT Subject Test Japanese with Listening'), ('SAT2_KOL', 'SAT Subject Test Korean with Listening'), ('AP_RSRCH', 'AP Research'), ('AP_SMNR', 'AP Seminar'), ('AP_ART2D', 'AP Art and Design: 2-D Design'), ('AP_ART3D', 'AP Art and Design: 3-D Design'), ('AP_ARTDRAW', 'AP Art and Design: Drawing'), ('AP_ARTHIST', 'AP Art History'), ('AP_BIO', 'AP Biology'), ('AP_CALCAB', 'AP Calculus AB'), ('AP_CALCBC', 'AP Calculus BC'), ('AP_CHEM', 'AP Chemistry'), ('AP_ZHLANG', 'AP Chinese Language and Culture'), ('AP_CSA', 'AP Computer Science A'), ('AP_CSP', 'AP Computer Science Principles'), ('AP_ENLANG', 'AP English Language and Composition'), ('AP_ENLIT', 'AP English Literature and Composition'), ('AP_ENVSCI', 'AP Environmental Science'), ('AP_EUROHIST', 'AP European History'), ('AP_FRLANG', 'AP French Language and Culture'), ('AP_DELANG', 'AP German Language and Culture'), ('AP_GOVCOMP', 'AP Comparative Government and Politics'), ('AP_GOVUS', 'AP U.S. Government and Politics'), ('AP_HUG', 'AP Human Geography'), ('AP_ITLANG', 'AP Italian Language and Culture'), ('AP_JALANG', 'AP Japanese Language and Culture'), ('AP_LATIN', 'AP Latin'), ('AP_MACRO', 'AP Macroeconomics'), ('AP_MICRO', 'AP Microeconomics'), ('AP_MUSTHRY', 'AP Music Theory'), ('AP_PHYSICS1', 'AP Physics 1: Algebra-Based'), ('AP_PHYSICS2', 'AP Physics 2: Algebra-Based'), ('AP_PHYSICSCEM', 'AP Physics C: Electricity and Magnetism'), ('AP_PHYSICSCM', 'AP Physics C: Mechanics'), ('AP_PSYCH', 'AP Psychology'), ('AP_ESLANG', 'AP Spanish Language and Culture'), ('AP_ESLIT', 'AP Spanish Literature and Culture'), ('AP_STAT', 'AP Statistics'), ('AP_USH', 'AP US History'), ('AP_WHM', 'AP World History: Modern')], max_length=20)), "id",
('exam_score', models.PositiveSmallIntegerField()), models.BigAutoField(
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"exam_type",
models.CharField(
choices=[
("ACT_ENGL", "ACT English (Grammar)"),
("ACT_MATH", "ACT Math"),
("ACT_READ", "ACT Reading"),
("ACT_SCI", "ACT Science"),
("ACT_COMP", "ACT Composite"),
("SAT_EBRW", "SAT Verbal"),
("SAT_MATH", "SAT Math"),
("SAT_TOTAL", "SAT Total"),
("SAT2_MATH1", "SAT Subject Test Math 1"),
("SAT2_MATH2", "SAT Subject Test Math 2"),
("SAT2_BIO", "SAT Subject Test Biology"),
("SAT2_CHEM", "SAT Subject Test Chemistry"),
("SAT2_PHYS", "SAT Subject Test Physics"),
("SAT2_ENGL", "SAT Subject Test English"),
("SAT2_USH", "SAT Subject Test U.S. History"),
("SAT2_WH", "SAT Subject Test World History"),
("SAT2_ES", "SAT Subject Test Spanish"),
("SAT2_ESL", "SAT Subject Test Spanish with Listening"),
("SAT2_FR", "SAT Subject Test French"),
("SAT2_FRL", "SAT Subject Test French with Listening"),
("SAT2_ZHL", "SAT Subject Test Chinese with Listening"),
("SAT2_IT", "SAT Subject Test Italian"),
("SAT2_DE", "SAT Subject Test German"),
("SAT2_DEL", "SAT Subject Test German with Listening"),
("SAT2_HE", "SAT Subject Test Modern Hebrew"),
("SAT2_LA", "SAT Subject Test Latin"),
("SAT2_JAL", "SAT Subject Test Japanese with Listening"),
("SAT2_KOL", "SAT Subject Test Korean with Listening"),
("AP_RSRCH", "AP Research"),
("AP_SMNR", "AP Seminar"),
("AP_ART2D", "AP Art and Design: 2-D Design"),
("AP_ART3D", "AP Art and Design: 3-D Design"),
("AP_ARTDRAW", "AP Art and Design: Drawing"),
("AP_ARTHIST", "AP Art History"),
("AP_BIO", "AP Biology"),
("AP_CALCAB", "AP Calculus AB"),
("AP_CALCBC", "AP Calculus BC"),
("AP_CHEM", "AP Chemistry"),
("AP_ZHLANG", "AP Chinese Language and Culture"),
("AP_CSA", "AP Computer Science A"),
("AP_CSP", "AP Computer Science Principles"),
("AP_ENLANG", "AP English Language and Composition"),
("AP_ENLIT", "AP English Literature and Composition"),
("AP_ENVSCI", "AP Environmental Science"),
("AP_EUROHIST", "AP European History"),
("AP_FRLANG", "AP French Language and Culture"),
("AP_DELANG", "AP German Language and Culture"),
("AP_GOVCOMP", "AP Comparative Government and Politics"),
("AP_GOVUS", "AP U.S. Government and Politics"),
("AP_HUG", "AP Human Geography"),
("AP_ITLANG", "AP Italian Language and Culture"),
("AP_JALANG", "AP Japanese Language and Culture"),
("AP_LATIN", "AP Latin"),
("AP_MACRO", "AP Macroeconomics"),
("AP_MICRO", "AP Microeconomics"),
("AP_MUSTHRY", "AP Music Theory"),
("AP_PHYSICS1", "AP Physics 1: Algebra-Based"),
("AP_PHYSICS2", "AP Physics 2: Algebra-Based"),
(
"AP_PHYSICSCEM",
"AP Physics C: Electricity and Magnetism",
),
("AP_PHYSICSCM", "AP Physics C: Mechanics"),
("AP_PSYCH", "AP Psychology"),
("AP_ESLANG", "AP Spanish Language and Culture"),
("AP_ESLIT", "AP Spanish Literature and Culture"),
("AP_STAT", "AP Statistics"),
("AP_USH", "AP US History"),
("AP_WHM", "AP World History: Modern"),
],
max_length=20,
),
),
("exam_score", models.PositiveSmallIntegerField()),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
name='Decision', name="Decision",
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('decision_type', models.CharField(choices=[('ED', 'Early Decision'), ('ED2', 'Early Decision 2'), ('EA', 'Early Action'), ('EA2', 'Early Action 2'), ('RD', 'Regular Decision'), ('RL', 'Rolling')], max_length=20, null=True)), "id",
('college', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='destinations.college')), models.BigAutoField(
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"decision_type",
models.CharField(
choices=[
("ED", "Early Decision"),
("ED2", "Early Decision 2"),
("EA", "Early Action"),
("EA2", "Early Action 2"),
("RD", "Regular Decision"),
("RL", "Rolling"),
],
max_length=20,
null=True,
),
),
(
"college",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="destinations.college",
),
),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
], ],
), ),
] ]

View File

@ -6,13 +6,13 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('destinations', '0001_initial'), ("destinations", "0001_initial"),
] ]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='decision', model_name="decision",
name='admitted', name="admitted",
field=models.BooleanField(default=False), field=models.BooleanField(default=False),
), ),
] ]

View File

@ -6,13 +6,26 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('destinations', '0002_decision_admitted'), ("destinations", "0002_decision_admitted"),
] ]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='decision', model_name="decision",
name='admitted', name="admitted",
field=models.CharField(choices=[('ADMIT', 'Admitted'), ('WAITLIST', 'Waitlisted'), ('WAITLIST_ADMIT', 'Waitlist-Admitted'), ('WAITLIST_DENY', 'Waitlist-Denied'), ('DEFER', 'Deferred'), ('DEFER_ADMIT', 'Deferred-Admitted'), ('DEFER_DENY', 'Deferred-Denied'), ('DENY', 'Denied')], default='DENY', max_length=20), field=models.CharField(
choices=[
("ADMIT", "Admitted"),
("WAITLIST", "Waitlisted"),
("WAITLIST_ADMIT", "Waitlist-Admitted"),
("WAITLIST_DENY", "Waitlist-Denied"),
("DEFER", "Deferred"),
("DEFER_ADMIT", "Deferred-Admitted"),
("DEFER_DENY", "Deferred-Denied"),
("DENY", "Denied"),
],
default="DENY",
max_length=20,
),
), ),
] ]

View File

@ -6,13 +6,13 @@ from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('destinations', '0003_alter_decision_admitted'), ("destinations", "0003_alter_decision_admitted"),
] ]
operations = [ operations = [
migrations.RenameField( migrations.RenameField(
model_name='decision', model_name="decision",
old_name='admitted', old_name="admitted",
new_name='admission_status', new_name="admission_status",
), ),
] ]

View File

@ -6,13 +6,25 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('destinations', '0004_rename_admitted_decision_admission_status'), ("destinations", "0004_rename_admitted_decision_admission_status"),
] ]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='decision', model_name="decision",
name='admission_status', name="admission_status",
field=models.CharField(choices=[('ADMIT', 'Admitted'), ('WAITLIST', 'Waitlisted'), ('WAITLIST_ADMIT', 'Waitlist-Admitted'), ('WAITLIST_DENY', 'Waitlist-Denied'), ('DEFER', 'Deferred'), ('DEFER_ADMIT', 'Deferred-Admitted'), ('DEFER_DENY', 'Deferred-Denied'), ('DENY', 'Denied')], max_length=20), field=models.CharField(
choices=[
("ADMIT", "Admitted"),
("WAITLIST", "Waitlisted"),
("WAITLIST_ADMIT", "Waitlist-Admitted"),
("WAITLIST_DENY", "Waitlist-Denied"),
("DEFER", "Deferred"),
("DEFER_ADMIT", "Deferred-Admitted"),
("DEFER_DENY", "Deferred-Denied"),
("DENY", "Denied"),
],
max_length=20,
),
), ),
] ]

View File

@ -6,13 +6,13 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('destinations', '0005_alter_decision_admission_status'), ("destinations", "0005_alter_decision_admission_status"),
] ]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='college', model_name="college",
name='ceeb_code', name="ceeb_code",
field=models.CharField(max_length=10, verbose_name='CEEB Code'), field=models.CharField(max_length=10, verbose_name="CEEB Code"),
), ),
] ]

View File

@ -4,7 +4,8 @@ from django.db import models
class College(models.Model): class College(models.Model):
"""Represents a college.""" """Represents a college."""
ceeb_code = models.CharField(max_length=10, null=False, verbose_name="CEEB Code") ceeb_code = models.CharField(
max_length=10, null=False, verbose_name="CEEB Code")
name = models.CharField(max_length=250, null=False, blank=False) name = models.CharField(max_length=250, null=False, blank=False)
location = models.CharField(max_length=250, null=False, blank=False) location = models.CharField(max_length=250, null=False, blank=False)
@ -33,7 +34,9 @@ class Decision(models.Model):
user = models.ForeignKey("authentication.User", on_delete=models.CASCADE) user = models.ForeignKey("authentication.User", on_delete=models.CASCADE)
decision_type = models.CharField(max_length=20, choices=DECISION_TYPE_CHOICES, null=True) decision_type = models.CharField(
max_length=20, choices=DECISION_TYPE_CHOICES, null=True
)
ADMIT = "ADMIT" ADMIT = "ADMIT"
WAITLIST_ADMIT = "WAITLIST_ADMIT" WAITLIST_ADMIT = "WAITLIST_ADMIT"
@ -55,7 +58,8 @@ class Decision(models.Model):
(DENY, "Denied"), (DENY, "Denied"),
] ]
admission_status = models.CharField(max_length=20, choices=ADMIT_TYPE_CHOICES) admission_status = models.CharField(
max_length=20, choices=ADMIT_TYPE_CHOICES)
college = models.ForeignKey(College, on_delete=models.CASCADE) college = models.ForeignKey(College, on_delete=models.CASCADE)
def __str__(self): def __str__(self):

View File

@ -1,4 +1,5 @@
from django.urls import path from django.urls import path
from . import views from . import views
app_name = "destinations" app_name = "destinations"

View File

@ -1,10 +1,10 @@
from django.contrib.auth.mixins import UserPassesTestMixin, LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.db.models import Count, Q from django.db.models import Count, Q
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.views.generic import ListView from django.views.generic import ListView
from .models import College, Decision
from ..authentication.models import User from ..authentication.models import User
from .models import College, Decision
class StudentDestinationListView(LoginRequiredMixin, UserPassesTestMixin, ListView): class StudentDestinationListView(LoginRequiredMixin, UserPassesTestMixin, ListView):
@ -12,7 +12,9 @@ class StudentDestinationListView(LoginRequiredMixin, UserPassesTestMixin, ListVi
paginate_by = 20 paginate_by = 20
def get_queryset(self): def get_queryset(self):
queryset = User.objects.filter(publish_data=True, is_senior=True).order_by("last_name", "first_name") queryset = User.objects.filter(publish_data=True, is_senior=True).order_by(
"last_name", "first_name"
)
college_id = self.request.GET.get("college", None) college_id = self.request.GET.get("college", None)
if college_id is not None: if college_id is not None:
@ -22,7 +24,8 @@ class StudentDestinationListView(LoginRequiredMixin, UserPassesTestMixin, ListVi
return queryset return queryset
def get_context_data(self, *, object_list=None, **kwargs): def get_context_data(self, *, object_list=None, **kwargs):
context = super(StudentDestinationListView, self).get_context_data(**kwargs) context = super(StudentDestinationListView,
self).get_context_data(**kwargs)
college_id = self.request.GET.get("college", None) college_id = self.request.GET.get("college", None)
if college_id is not None: if college_id is not None:
@ -39,31 +42,71 @@ class StudentDestinationListView(LoginRequiredMixin, UserPassesTestMixin, ListVi
class CollegeDestinationListView(LoginRequiredMixin, UserPassesTestMixin, ListView): class CollegeDestinationListView(LoginRequiredMixin, UserPassesTestMixin, ListView):
model = College model = College
paginate_by = 20 paginate_by = 20
queryset = College.objects.annotate(count_decisions=Count("decision", filter=Q(decision__user__publish_data=True)), queryset = (
count_admit=Count("decision", College.objects.annotate(
filter=Q(decision__admission_status=Decision.ADMIT, count_decisions=Count(
decision__user__publish_data=True)), "decision", filter=Q(decision__user__publish_data=True)
count_waitlist=Count("decision", ),
filter=Q(decision__admission_status=Decision.WAITLIST, count_admit=Count(
decision__user__publish_data=True)), "decision",
count_waitlist_admit=Count("decision", filter=Q( filter=Q(
decision__admission_status=Decision.WAITLIST_ADMIT, decision__admission_status=Decision.ADMIT,
decision__user__publish_data=True)), decision__user__publish_data=True,
count_waitlist_deny=Count("decision", filter=Q( ),
decision__admission_status=Decision.WAITLIST_DENY, ),
decision__user__publish_data=True)), count_waitlist=Count(
count_defer=Count("decision", "decision",
filter=Q(decision__admission_status=Decision.DEFER, filter=Q(
decision__user__publish_data=True)), decision__admission_status=Decision.WAITLIST,
count_defer_admit=Count("decision", filter=Q( decision__user__publish_data=True,
decision__admission_status=Decision.DEFER_ADMIT, ),
decision__user__publish_data=True)), ),
count_defer_deny=Count("decision", count_waitlist_admit=Count(
filter=Q(decision__admission_status=Decision.DEFER_DENY, "decision",
decision__user__publish_data=True)), filter=Q(
count_deny=Count("decision", filter=Q(decision__admission_status=Decision.DENY, decision__admission_status=Decision.WAITLIST_ADMIT,
decision__user__publish_data=True)), decision__user__publish_data=True,
).filter(count_decisions__gte=1).order_by("name") ),
),
count_waitlist_deny=Count(
"decision",
filter=Q(
decision__admission_status=Decision.WAITLIST_DENY,
decision__user__publish_data=True,
),
),
count_defer=Count(
"decision",
filter=Q(
decision__admission_status=Decision.DEFER,
decision__user__publish_data=True,
),
),
count_defer_admit=Count(
"decision",
filter=Q(
decision__admission_status=Decision.DEFER_ADMIT,
decision__user__publish_data=True,
),
),
count_defer_deny=Count(
"decision",
filter=Q(
decision__admission_status=Decision.DEFER_DENY,
decision__user__publish_data=True,
),
),
count_deny=Count(
"decision",
filter=Q(
decision__admission_status=Decision.DENY,
decision__user__publish_data=True,
),
),
)
.filter(count_decisions__gte=1)
.order_by("name")
)
def test_func(self): def test_func(self):
return self.request.user.accepted_terms return self.request.user.accepted_terms

View File

@ -1,10 +1,8 @@
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit
from django import forms from django import forms
from tjdests.apps.authentication.models import User from tjdests.apps.authentication.models import User
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit
from tjdests.apps.destinations.models import Decision from tjdests.apps.destinations.models import Decision
@ -12,16 +10,24 @@ class ProfilePublishForm(forms.ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.helper = FormHelper() self.helper = FormHelper()
self.helper.form_method = 'post' self.helper.form_method = "post"
self.helper.add_input(Submit('submit', 'Submit')) self.helper.add_input(Submit("submit", "Submit"))
self.fields["attending_decision"].queryset = Decision.objects.filter(user=self.instance, admission_status__in=[Decision.ADMIT, Decision.WAITLIST_ADMIT, Decision.DEFER_ADMIT]) self.fields["attending_decision"].queryset = Decision.objects.filter(
user=self.instance,
admission_status__in=[
Decision.ADMIT,
Decision.WAITLIST_ADMIT,
Decision.DEFER_ADMIT,
],
)
class Meta: class Meta:
model = User model = User
fields = ["publish_data", "biography", "attending_decision"] fields = ["publish_data", "biography", "attending_decision"]
class DecisionForm(forms.ModelForm): class DecisionForm(forms.ModelForm):
class Meta: class Meta:
model = Decision model = Decision

View File

@ -1,4 +1,5 @@
from django.urls import path from django.urls import path
from . import views from . import views
app_name = "profile" app_name = "profile"
@ -6,9 +7,25 @@ app_name = "profile"
urlpatterns = [ urlpatterns = [
path("", views.profile_view, name="index"), path("", views.profile_view, name="index"),
path("testscore/add", views.TestScoreCreateView.as_view(), name="testscores_add"), path("testscore/add", views.TestScoreCreateView.as_view(), name="testscores_add"),
path("testscore/edit/<int:pk>", views.TestScoreUpdateView.as_view(), name="testscores_edit"), path(
path("testscore/delete/<int:pk>", views.TestScoreDeleteView.as_view(), name="testscores_delete"), "testscore/edit/<int:pk>",
views.TestScoreUpdateView.as_view(),
name="testscores_edit",
),
path(
"testscore/delete/<int:pk>",
views.TestScoreDeleteView.as_view(),
name="testscores_delete",
),
path("decision/add", views.DecisionCreateView.as_view(), name="decision_add"), path("decision/add", views.DecisionCreateView.as_view(), name="decision_add"),
path("decision/edit/<int:pk>", views.DecisionUpdateView.as_view(), name="decision_edit"), path(
path("decision/delete/<int:pk>", views.DecisionDeleteView.as_view(), name="decision_delete"), "decision/edit/<int:pk>",
views.DecisionUpdateView.as_view(),
name="decision_edit",
),
path(
"decision/delete/<int:pk>",
views.DecisionDeleteView.as_view(),
name="decision_delete",
),
] ]

View File

@ -1,16 +1,16 @@
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import UserPassesTestMixin, LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib.messages.views import SuccessMessageMixin from django.contrib.messages.views import SuccessMessageMixin
from django.http import HttpRequest from django.http import HttpRequest
from django.shortcuts import render from django.shortcuts import render
from django.urls import reverse from django.urls import reverse
from django.views.generic import CreateView, UpdateView, DeleteView from django.views.generic import CreateView, DeleteView, UpdateView
from tjdests.apps.authentication.decorators import require_accept_tos from tjdests.apps.authentication.decorators import require_accept_tos
from tjdests.apps.destinations.models import TestScore, Decision from tjdests.apps.destinations.models import Decision, TestScore
from .forms import ProfilePublishForm, DecisionForm from .forms import DecisionForm, ProfilePublishForm
@login_required @login_required
@ -29,12 +29,18 @@ def profile_view(request: HttpRequest):
else: else:
profile_form = ProfilePublishForm(instance=request.user) profile_form = ProfilePublishForm(instance=request.user)
context = {"test_scores_list": test_scores, "decisions_list": decisions, "profile_form": profile_form} context = {
"test_scores_list": test_scores,
"decisions_list": decisions,
"profile_form": profile_form,
}
return render(request, "profile/profile.html", context=context) return render(request, "profile/profile.html", context=context)
class TestScoreCreateView(LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, CreateView): class TestScoreCreateView(
LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, CreateView
):
model = TestScore model = TestScore
fields = ["exam_type", "exam_score"] fields = ["exam_type", "exam_score"]
template_name = "profile/testscore_form.html" template_name = "profile/testscore_form.html"
@ -51,7 +57,9 @@ class TestScoreCreateView(LoginRequiredMixin, SuccessMessageMixin, UserPassesTes
return reverse("profile:index") return reverse("profile:index")
class TestScoreUpdateView(LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, UpdateView): class TestScoreUpdateView(
LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, UpdateView
):
model = TestScore model = TestScore
fields = ["exam_type", "exam_score"] fields = ["exam_type", "exam_score"]
template_name = "profile/testscore_form.html" template_name = "profile/testscore_form.html"
@ -72,7 +80,9 @@ class TestScoreUpdateView(LoginRequiredMixin, SuccessMessageMixin, UserPassesTes
return reverse("profile:index") return reverse("profile:index")
class TestScoreDeleteView(LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, DeleteView): class TestScoreDeleteView(
LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, DeleteView
):
model = TestScore model = TestScore
template_name = "profile/testscore_delete.html" template_name = "profile/testscore_delete.html"
success_message = "Test score deleted successfully." success_message = "Test score deleted successfully."
@ -87,7 +97,10 @@ class TestScoreDeleteView(LoginRequiredMixin, SuccessMessageMixin, UserPassesTes
def get_success_url(self): def get_success_url(self):
return reverse("profile:index") return reverse("profile:index")
class DecisionCreateView(LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, CreateView):
class DecisionCreateView(
LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, CreateView
):
model = Decision model = Decision
fields = ["college", "decision_type", "admission_status"] fields = ["college", "decision_type", "admission_status"]
template_name = "profile/decision_form.html" template_name = "profile/decision_form.html"
@ -104,7 +117,9 @@ class DecisionCreateView(LoginRequiredMixin, SuccessMessageMixin, UserPassesTest
return reverse("profile:index") return reverse("profile:index")
class DecisionUpdateView(LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, UpdateView): class DecisionUpdateView(
LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, UpdateView
):
model = Decision model = Decision
fields = ["college", "decision_type", "admission_status"] fields = ["college", "decision_type", "admission_status"]
template_name = "profile/decision_form.html" template_name = "profile/decision_form.html"
@ -125,7 +140,9 @@ class DecisionUpdateView(LoginRequiredMixin, SuccessMessageMixin, UserPassesTest
return reverse("profile:index") return reverse("profile:index")
class DecisionDeleteView(LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, DeleteView): class DecisionDeleteView(
LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, DeleteView
):
model = Decision model = Decision
template_name = "profile/decision_delete.html" template_name = "profile/decision_delete.html"
success_message = "Decision deleted successfully." success_message = "Decision deleted successfully."

View File

@ -11,6 +11,6 @@ import os
from django.core.asgi import get_asgi_application from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tjdests.settings') os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tjdests.settings")
application = get_asgi_application() application = get_asgi_application()

View File

@ -21,7 +21,7 @@ BASE_DIR = Path(__file__).resolve().parent.parent
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ # See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret! # SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-7nju0o%j&gz7&v^05iuq*tn$_iwvtjh1cq26@is(u2d4snkum5' SECRET_KEY = "django-insecure-7nju0o%j&gz7&v^05iuq*tn$_iwvtjh1cq26@is(u2d4snkum5"
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True DEBUG = True
@ -32,62 +32,61 @@ ALLOWED_HOSTS = []
# Application definition # Application definition
INSTALLED_APPS = [ INSTALLED_APPS = [
'django.contrib.admin', "django.contrib.admin",
'django.contrib.auth', "django.contrib.auth",
'django.contrib.contenttypes', "django.contrib.contenttypes",
'django.contrib.sessions', "django.contrib.sessions",
'django.contrib.messages', "django.contrib.messages",
'django.contrib.staticfiles', "django.contrib.staticfiles",
"crispy_forms", "crispy_forms",
"crispy_bootstrap5", "crispy_bootstrap5",
"social_django", "social_django",
"django_extensions", "django_extensions",
"bootstrap_pagination", "bootstrap_pagination",
'tjdests.apps.authentication', "tjdests.apps.authentication",
'tjdests.apps.destinations', "tjdests.apps.destinations",
"tjdests.apps.profile", "tjdests.apps.profile",
] ]
MIDDLEWARE = [ MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', "django.middleware.security.SecurityMiddleware",
'django.contrib.sessions.middleware.SessionMiddleware', "django.contrib.sessions.middleware.SessionMiddleware",
'django.middleware.common.CommonMiddleware', "django.middleware.common.CommonMiddleware",
'django.middleware.csrf.CsrfViewMiddleware', "django.middleware.csrf.CsrfViewMiddleware",
'django.contrib.auth.middleware.AuthenticationMiddleware', "django.contrib.auth.middleware.AuthenticationMiddleware",
'django.contrib.messages.middleware.MessageMiddleware', "django.contrib.messages.middleware.MessageMiddleware",
'django.middleware.clickjacking.XFrameOptionsMiddleware', "django.middleware.clickjacking.XFrameOptionsMiddleware",
] ]
ROOT_URLCONF = 'tjdests.urls' ROOT_URLCONF = "tjdests.urls"
TEMPLATES = [ TEMPLATES = [
{ {
'BACKEND': 'django.template.backends.django.DjangoTemplates', "BACKEND": "django.template.backends.django.DjangoTemplates",
'DIRS': [BASE_DIR / 'templates'] "DIRS": [BASE_DIR / "templates"],
, "APP_DIRS": True,
'APP_DIRS': True, "OPTIONS": {
'OPTIONS': { "context_processors": [
'context_processors': [ "django.template.context_processors.debug",
'django.template.context_processors.debug', "django.template.context_processors.request",
'django.template.context_processors.request', "django.contrib.auth.context_processors.auth",
'django.contrib.auth.context_processors.auth', "django.contrib.messages.context_processors.messages",
'django.contrib.messages.context_processors.messages', "tjdests.apps.context_processors.settings_renderer",
'tjdests.apps.context_processors.settings_renderer',
], ],
}, },
}, },
] ]
WSGI_APPLICATION = 'tjdests.wsgi.application' WSGI_APPLICATION = "tjdests.wsgi.application"
# Database # Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases # https://docs.djangoproject.com/en/3.2/ref/settings/#databases
DATABASES = { DATABASES = {
'default': { "default": {
'ENGINE': 'django.db.backends.sqlite3', "ENGINE": "django.db.backends.sqlite3",
'NAME': BASE_DIR / 'db.sqlite3', "NAME": BASE_DIR / "db.sqlite3",
} }
} }
@ -97,22 +96,25 @@ DATABASES = {
AUTH_PASSWORD_VALIDATORS = [ AUTH_PASSWORD_VALIDATORS = [
{ {
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
}, },
{ {
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
}, },
{ {
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
}, },
{ {
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
}, },
] ]
AUTH_USER_MODEL = "authentication.User" AUTH_USER_MODEL = "authentication.User"
AUTHENTICATION_BACKENDS = ("tjdests.apps.authentication.oauth.IonOauth2", "django.contrib.auth.backends.ModelBackend",) AUTHENTICATION_BACKENDS = (
"tjdests.apps.authentication.oauth.IonOauth2",
"django.contrib.auth.backends.ModelBackend",
)
SOCIAL_AUTH_REDIRECT_IS_HTTPS = False SOCIAL_AUTH_REDIRECT_IS_HTTPS = False
SOCIAL_AUTH_ION_KEY = "" SOCIAL_AUTH_ION_KEY = ""
@ -122,9 +124,9 @@ SOCIAL_AUTH_ION_SECRET = ""
# Internationalization # Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/ # https://docs.djangoproject.com/en/3.2/topics/i18n/
LANGUAGE_CODE = 'en-us' LANGUAGE_CODE = "en-us"
TIME_ZONE = 'UTC' TIME_ZONE = "UTC"
USE_I18N = True USE_I18N = True
@ -136,14 +138,14 @@ USE_TZ = True
# Static files (CSS, JavaScript, Images) # Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/ # https://docs.djangoproject.com/en/3.2/howto/static-files/
STATIC_URL = '/static/' STATIC_URL = "/static/"
STATIC_ROOT = os.path.join(BASE_DIR, "serve/") STATIC_ROOT = os.path.join(BASE_DIR, "serve/")
STATICFILES_DIRS = (os.path.join(BASE_DIR, "static/"),) STATICFILES_DIRS = (os.path.join(BASE_DIR, "static/"),)
# Default primary key field type # Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
LOGIN_REDIRECT_URL = "authentication:tos" LOGIN_REDIRECT_URL = "authentication:tos"
LOGOUT_REDIRECT_URL = "authentication:index" LOGOUT_REDIRECT_URL = "authentication:index"

View File

@ -10,7 +10,7 @@ DEBUG = True
ALLOWED_HOSTS = [] ALLOWED_HOSTS = []
# secret # secret
SECRET_KEY = 'supersecret' SECRET_KEY = "supersecret"
# OAuth # OAuth
SOCIAL_AUTH_ION_KEY = "ionkey" SOCIAL_AUTH_ION_KEY = "ionkey"

View File

@ -14,12 +14,15 @@ Including another URLconf
2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
""" """
from django.contrib import admin from django.contrib import admin
from django.urls import path, include from django.urls import include, path
urlpatterns = [ urlpatterns = [
path('djangoadmin/', admin.site.urls), path("djangoadmin/", admin.site.urls),
path("", include("tjdests.apps.authentication.urls", namespace="authentication")), path("", include("tjdests.apps.authentication.urls", namespace="authentication")),
path("oauth/", include("social_django.urls", namespace="social")), path("oauth/", include("social_django.urls", namespace="social")),
path("destinations/", include("tjdests.apps.destinations.urls", namespace="destinations")), path(
"destinations/",
include("tjdests.apps.destinations.urls", namespace="destinations"),
),
path("profile/", include("tjdests.apps.profile.urls", namespace="profile")), path("profile/", include("tjdests.apps.profile.urls", namespace="profile")),
] ]

View File

@ -11,6 +11,6 @@ import os
from django.core.wsgi import get_wsgi_application from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tjdests.settings') os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tjdests.settings")
application = get_wsgi_application() application = get_wsgi_application()