mirror of
https://github.com/etnguyen03/tjdests.git
synced 2025-04-28 12:49:49 -04:00
style: reformat
This commit is contained in:
parent
9ad55a731d
commit
337d3e2f35
35
scripts/format.sh
Executable file
35
scripts/format.sh
Executable 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
|
|
@ -12,4 +12,4 @@ def require_accept_tos(func):
|
|||
|
||||
return func(request, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
return wrapper
|
||||
|
|
|
@ -1,47 +1,69 @@
|
|||
from django import forms
|
||||
from django.contrib.auth import password_validation
|
||||
|
||||
from crispy_forms.helper import FormHelper
|
||||
from crispy_forms.layout import Submit
|
||||
from django import forms
|
||||
from django.contrib.auth import password_validation
|
||||
|
||||
|
||||
class TOSForm(forms.Form):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
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,"
|
||||
" 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.")
|
||||
accept_tos = forms.BooleanField(
|
||||
required=True,
|
||||
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_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):
|
||||
cleaned_data = super(TOSForm, self).clean()
|
||||
password1 = cleaned_data.get('password')
|
||||
password2 = cleaned_data.get('password_confirm')
|
||||
password1 = cleaned_data.get("password")
|
||||
password2 = cleaned_data.get("password_confirm")
|
||||
|
||||
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
|
||||
accept_tos = cleaned_data.get("accept_tos")
|
||||
understand_no_reset = cleaned_data.get("understand_no_reset")
|
||||
|
||||
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:
|
||||
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.
|
||||
validators = password_validation.get_default_password_validators()
|
||||
password_validation.validate_password(password1, None, validators)
|
||||
|
||||
|
||||
|
|
|
@ -2,45 +2,117 @@
|
|||
|
||||
import django.contrib.auth.models
|
||||
import django.contrib.auth.validators
|
||||
from django.db import migrations, models
|
||||
import django.utils.timezone
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
dependencies = []
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='User',
|
||||
name="User",
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
||||
('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)),
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("password", models.CharField(
|
||||
max_length=128, verbose_name="password")),
|
||||
(
|
||||
"last_login",
|
||||
models.DateTimeField(
|
||||
blank=True, null=True, verbose_name="last login"
|
||||
),
|
||||
),
|
||||
(
|
||||
"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={
|
||||
'verbose_name': 'user',
|
||||
'verbose_name_plural': 'users',
|
||||
'abstract': False,
|
||||
"verbose_name": "user",
|
||||
"verbose_name_plural": "users",
|
||||
"abstract": False,
|
||||
},
|
||||
managers=[
|
||||
('objects', django.contrib.auth.models.UserManager()),
|
||||
("objects", django.contrib.auth.models.UserManager()),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Generated by Django 3.2 on 2021-04-19 15:03
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
@ -9,25 +9,46 @@ class Migration(migrations.Migration):
|
|||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('auth', '0012_alter_user_first_name_max_length'),
|
||||
('authentication', '0001_initial'),
|
||||
('destinations', '0001_initial'),
|
||||
("auth", "0012_alter_user_first_name_max_length"),
|
||||
("authentication", "0001_initial"),
|
||||
("destinations", "0001_initial"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
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'),
|
||||
model_name="user",
|
||||
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",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
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'),
|
||||
model_name="user",
|
||||
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(
|
||||
model_name='user',
|
||||
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'),
|
||||
model_name="user",
|
||||
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",
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -6,13 +6,17 @@ from django.db import migrations, models
|
|||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('authentication', '0002_initial'),
|
||||
("authentication", "0002_initial"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='user',
|
||||
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'),
|
||||
model_name="user",
|
||||
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",
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -1,25 +1,33 @@
|
|||
# Generated by Django 3.2 on 2021-04-19 17:13
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('destinations', '0005_alter_decision_admission_status'),
|
||||
('authentication', '0003_alter_user_publish_data'),
|
||||
("destinations", "0005_alter_decision_admission_status"),
|
||||
("authentication", "0003_alter_user_publish_data"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='is_student',
|
||||
model_name="user",
|
||||
name="is_student",
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='user',
|
||||
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'),
|
||||
model_name="user",
|
||||
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",
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
from django.db import models
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.db import models
|
||||
|
||||
from ..destinations.models import Decision, TestScore
|
||||
|
||||
|
||||
class User(AbstractUser):
|
||||
accepted_terms = models.BooleanField(default=False)
|
||||
graduation_year = models.PositiveSmallIntegerField(null=True)
|
||||
|
@ -11,12 +12,22 @@ class User(AbstractUser):
|
|||
is_student = models.BooleanField(default=False)
|
||||
|
||||
# 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)
|
||||
|
||||
attending_decision = models.ForeignKey(Decision, 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.")
|
||||
attending_decision = models.ForeignKey(
|
||||
Decision,
|
||||
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):
|
||||
return f"{self.first_name} {self.last_name}"
|
||||
|
|
|
@ -7,14 +7,16 @@ class IonOauth2(BaseOAuth2):
|
|||
AUTHORIZATION_URL = "https://ion.tjhsst.edu/oauth/authorize"
|
||||
ACCESS_TOKEN_URL = "https://ion.tjhsst.edu/oauth/token"
|
||||
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):
|
||||
return ["read"]
|
||||
|
||||
def get_user_details(self, response):
|
||||
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
|
||||
|
||||
|
@ -31,8 +33,8 @@ class IonOauth2(BaseOAuth2):
|
|||
"is_student": profile["is_student"],
|
||||
"is_teacher": profile["is_teacher"],
|
||||
"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):
|
||||
return details["id"]
|
||||
return details["id"]
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from django.contrib.auth.views import LogoutView
|
||||
from django.urls import path
|
||||
|
||||
from . import views
|
||||
|
||||
app_name = "authentication"
|
||||
|
@ -9,4 +10,4 @@ urlpatterns = [
|
|||
path("login", views.LoginViewCustom.as_view(), name="login"),
|
||||
path("logout", LogoutView.as_view(), name="logout"),
|
||||
path("tos", views.accept_tos_view, name="tos"),
|
||||
]
|
||||
]
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
from django.contrib import messages
|
||||
from django.contrib.auth import login, logout
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.views import LoginView
|
||||
from django.contrib import messages
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.shortcuts import render, redirect
|
||||
from django.shortcuts import redirect, render
|
||||
from django.urls import reverse
|
||||
|
||||
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:
|
||||
return render(request, "authentication/index.html")
|
||||
|
||||
|
||||
@login_required
|
||||
def accept_tos_view(request: HttpRequest) -> HttpResponse:
|
||||
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.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.")
|
||||
|
||||
|
@ -45,6 +50,6 @@ def accept_tos_view(request: HttpRequest) -> HttpResponse:
|
|||
|
||||
return render(request, "authentication/accept_tos.html", context=context)
|
||||
|
||||
|
||||
class LoginViewCustom(LoginView):
|
||||
template_name = "authentication/login.html"
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from django.conf import settings
|
||||
|
||||
|
||||
def settings_renderer(request):
|
||||
return {"settings": settings}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from .models import College, TestScore, Decision
|
||||
from .models import College, Decision, TestScore
|
||||
|
||||
admin.site.register(College)
|
||||
admin.site.register(TestScore)
|
||||
|
|
|
@ -5,6 +5,7 @@ from django.core.management.base import BaseCommand
|
|||
|
||||
from ...models import College
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Imports a CSV of CEEB codes as colleges"
|
||||
|
||||
|
@ -20,9 +21,21 @@ class Command(BaseCommand):
|
|||
reader = csv.DictReader(file)
|
||||
|
||||
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]:
|
||||
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:
|
||||
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,
|
||||
)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# Generated by Django 3.2 on 2021-04-19 15:03
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
@ -15,30 +15,165 @@ class Migration(migrations.Migration):
|
|||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='College',
|
||||
name="College",
|
||||
fields=[
|
||||
('id', models.BigAutoField(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)),
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
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(
|
||||
name='TestScore',
|
||||
name="TestScore",
|
||||
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)),
|
||||
('exam_score', models.PositiveSmallIntegerField()),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
(
|
||||
"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,
|
||||
),
|
||||
),
|
||||
("exam_score", models.PositiveSmallIntegerField()),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Decision',
|
||||
name="Decision",
|
||||
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)),
|
||||
('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)),
|
||||
(
|
||||
"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,
|
||||
),
|
||||
),
|
||||
(
|
||||
"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,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
|
|
@ -6,13 +6,13 @@ from django.db import migrations, models
|
|||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('destinations', '0001_initial'),
|
||||
("destinations", "0001_initial"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='decision',
|
||||
name='admitted',
|
||||
model_name="decision",
|
||||
name="admitted",
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -6,13 +6,26 @@ from django.db import migrations, models
|
|||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('destinations', '0002_decision_admitted'),
|
||||
("destinations", "0002_decision_admitted"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='decision',
|
||||
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),
|
||||
model_name="decision",
|
||||
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,
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -6,13 +6,13 @@ from django.db import migrations
|
|||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('destinations', '0003_alter_decision_admitted'),
|
||||
("destinations", "0003_alter_decision_admitted"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='decision',
|
||||
old_name='admitted',
|
||||
new_name='admission_status',
|
||||
model_name="decision",
|
||||
old_name="admitted",
|
||||
new_name="admission_status",
|
||||
),
|
||||
]
|
||||
|
|
|
@ -6,13 +6,25 @@ from django.db import migrations, models
|
|||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('destinations', '0004_rename_admitted_decision_admission_status'),
|
||||
("destinations", "0004_rename_admitted_decision_admission_status"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='decision',
|
||||
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),
|
||||
model_name="decision",
|
||||
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,
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -6,13 +6,13 @@ from django.db import migrations, models
|
|||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('destinations', '0005_alter_decision_admission_status'),
|
||||
("destinations", "0005_alter_decision_admission_status"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='college',
|
||||
name='ceeb_code',
|
||||
field=models.CharField(max_length=10, verbose_name='CEEB Code'),
|
||||
model_name="college",
|
||||
name="ceeb_code",
|
||||
field=models.CharField(max_length=10, verbose_name="CEEB Code"),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -4,7 +4,8 @@ from django.db import models
|
|||
class College(models.Model):
|
||||
"""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)
|
||||
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)
|
||||
|
||||
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"
|
||||
WAITLIST_ADMIT = "WAITLIST_ADMIT"
|
||||
|
@ -55,7 +58,8 @@ class Decision(models.Model):
|
|||
(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)
|
||||
|
||||
def __str__(self):
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from django.urls import path
|
||||
|
||||
from . import views
|
||||
|
||||
app_name = "destinations"
|
||||
|
@ -6,4 +7,4 @@ app_name = "destinations"
|
|||
urlpatterns = [
|
||||
path("", views.StudentDestinationListView.as_view(), name="students"),
|
||||
path("colleges", views.CollegeDestinationListView.as_view(), name="colleges"),
|
||||
]
|
||||
]
|
||||
|
|
|
@ -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.shortcuts import get_object_or_404
|
||||
from django.views.generic import ListView
|
||||
|
||||
from .models import College, Decision
|
||||
from ..authentication.models import User
|
||||
from .models import College, Decision
|
||||
|
||||
|
||||
class StudentDestinationListView(LoginRequiredMixin, UserPassesTestMixin, ListView):
|
||||
|
@ -12,7 +12,9 @@ class StudentDestinationListView(LoginRequiredMixin, UserPassesTestMixin, ListVi
|
|||
paginate_by = 20
|
||||
|
||||
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)
|
||||
if college_id is not None:
|
||||
|
@ -22,7 +24,8 @@ class StudentDestinationListView(LoginRequiredMixin, UserPassesTestMixin, ListVi
|
|||
return queryset
|
||||
|
||||
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)
|
||||
if college_id is not None:
|
||||
|
@ -39,31 +42,71 @@ class StudentDestinationListView(LoginRequiredMixin, UserPassesTestMixin, ListVi
|
|||
class CollegeDestinationListView(LoginRequiredMixin, UserPassesTestMixin, ListView):
|
||||
model = College
|
||||
paginate_by = 20
|
||||
queryset = College.objects.annotate(count_decisions=Count("decision", filter=Q(decision__user__publish_data=True)),
|
||||
count_admit=Count("decision",
|
||||
filter=Q(decision__admission_status=Decision.ADMIT,
|
||||
decision__user__publish_data=True)),
|
||||
count_waitlist=Count("decision",
|
||||
filter=Q(decision__admission_status=Decision.WAITLIST,
|
||||
decision__user__publish_data=True)),
|
||||
count_waitlist_admit=Count("decision", filter=Q(
|
||||
decision__admission_status=Decision.WAITLIST_ADMIT,
|
||||
decision__user__publish_data=True)),
|
||||
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")
|
||||
queryset = (
|
||||
College.objects.annotate(
|
||||
count_decisions=Count(
|
||||
"decision", filter=Q(decision__user__publish_data=True)
|
||||
),
|
||||
count_admit=Count(
|
||||
"decision",
|
||||
filter=Q(
|
||||
decision__admission_status=Decision.ADMIT,
|
||||
decision__user__publish_data=True,
|
||||
),
|
||||
),
|
||||
count_waitlist=Count(
|
||||
"decision",
|
||||
filter=Q(
|
||||
decision__admission_status=Decision.WAITLIST,
|
||||
decision__user__publish_data=True,
|
||||
),
|
||||
),
|
||||
count_waitlist_admit=Count(
|
||||
"decision",
|
||||
filter=Q(
|
||||
decision__admission_status=Decision.WAITLIST_ADMIT,
|
||||
decision__user__publish_data=True,
|
||||
),
|
||||
),
|
||||
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):
|
||||
return self.request.user.accepted_terms
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
from crispy_forms.helper import FormHelper
|
||||
from crispy_forms.layout import Submit
|
||||
from django import forms
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
@ -12,16 +10,24 @@ class ProfilePublishForm(forms.ModelForm):
|
|||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
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:
|
||||
model = User
|
||||
fields = ["publish_data", "biography", "attending_decision"]
|
||||
|
||||
|
||||
class DecisionForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Decision
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from django.urls import path
|
||||
|
||||
from . import views
|
||||
|
||||
app_name = "profile"
|
||||
|
@ -6,9 +7,25 @@ app_name = "profile"
|
|||
urlpatterns = [
|
||||
path("", views.profile_view, name="index"),
|
||||
path("testscore/add", views.TestScoreCreateView.as_view(), name="testscores_add"),
|
||||
path("testscore/edit/<int:pk>", views.TestScoreUpdateView.as_view(), name="testscores_edit"),
|
||||
path("testscore/delete/<int:pk>", views.TestScoreDeleteView.as_view(), name="testscores_delete"),
|
||||
path(
|
||||
"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/edit/<int:pk>", views.DecisionUpdateView.as_view(), name="decision_edit"),
|
||||
path("decision/delete/<int:pk>", views.DecisionDeleteView.as_view(), name="decision_delete"),
|
||||
]
|
||||
path(
|
||||
"decision/edit/<int:pk>",
|
||||
views.DecisionUpdateView.as_view(),
|
||||
name="decision_edit",
|
||||
),
|
||||
path(
|
||||
"decision/delete/<int:pk>",
|
||||
views.DecisionDeleteView.as_view(),
|
||||
name="decision_delete",
|
||||
),
|
||||
]
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
from django.contrib import messages
|
||||
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.http import HttpRequest
|
||||
from django.shortcuts import render
|
||||
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.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
|
||||
|
@ -29,12 +29,18 @@ def profile_view(request: HttpRequest):
|
|||
else:
|
||||
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)
|
||||
|
||||
|
||||
class TestScoreCreateView(LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, CreateView):
|
||||
class TestScoreCreateView(
|
||||
LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, CreateView
|
||||
):
|
||||
model = TestScore
|
||||
fields = ["exam_type", "exam_score"]
|
||||
template_name = "profile/testscore_form.html"
|
||||
|
@ -51,7 +57,9 @@ class TestScoreCreateView(LoginRequiredMixin, SuccessMessageMixin, UserPassesTes
|
|||
return reverse("profile:index")
|
||||
|
||||
|
||||
class TestScoreUpdateView(LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, UpdateView):
|
||||
class TestScoreUpdateView(
|
||||
LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, UpdateView
|
||||
):
|
||||
model = TestScore
|
||||
fields = ["exam_type", "exam_score"]
|
||||
template_name = "profile/testscore_form.html"
|
||||
|
@ -72,7 +80,9 @@ class TestScoreUpdateView(LoginRequiredMixin, SuccessMessageMixin, UserPassesTes
|
|||
return reverse("profile:index")
|
||||
|
||||
|
||||
class TestScoreDeleteView(LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, DeleteView):
|
||||
class TestScoreDeleteView(
|
||||
LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, DeleteView
|
||||
):
|
||||
model = TestScore
|
||||
template_name = "profile/testscore_delete.html"
|
||||
success_message = "Test score deleted successfully."
|
||||
|
@ -87,7 +97,10 @@ class TestScoreDeleteView(LoginRequiredMixin, SuccessMessageMixin, UserPassesTes
|
|||
def get_success_url(self):
|
||||
return reverse("profile:index")
|
||||
|
||||
class DecisionCreateView(LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, CreateView):
|
||||
|
||||
class DecisionCreateView(
|
||||
LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, CreateView
|
||||
):
|
||||
model = Decision
|
||||
fields = ["college", "decision_type", "admission_status"]
|
||||
template_name = "profile/decision_form.html"
|
||||
|
@ -104,7 +117,9 @@ class DecisionCreateView(LoginRequiredMixin, SuccessMessageMixin, UserPassesTest
|
|||
return reverse("profile:index")
|
||||
|
||||
|
||||
class DecisionUpdateView(LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, UpdateView):
|
||||
class DecisionUpdateView(
|
||||
LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, UpdateView
|
||||
):
|
||||
model = Decision
|
||||
fields = ["college", "decision_type", "admission_status"]
|
||||
template_name = "profile/decision_form.html"
|
||||
|
@ -125,7 +140,9 @@ class DecisionUpdateView(LoginRequiredMixin, SuccessMessageMixin, UserPassesTest
|
|||
return reverse("profile:index")
|
||||
|
||||
|
||||
class DecisionDeleteView(LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, DeleteView):
|
||||
class DecisionDeleteView(
|
||||
LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, DeleteView
|
||||
):
|
||||
model = Decision
|
||||
template_name = "profile/decision_delete.html"
|
||||
success_message = "Decision deleted successfully."
|
||||
|
|
|
@ -11,6 +11,6 @@ import os
|
|||
|
||||
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()
|
||||
|
|
|
@ -21,7 +21,7 @@ BASE_DIR = Path(__file__).resolve().parent.parent
|
|||
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
|
||||
|
||||
# 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!
|
||||
DEBUG = True
|
||||
|
@ -32,62 +32,61 @@ ALLOWED_HOSTS = []
|
|||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
"django.contrib.admin",
|
||||
"django.contrib.auth",
|
||||
"django.contrib.contenttypes",
|
||||
"django.contrib.sessions",
|
||||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
"crispy_forms",
|
||||
"crispy_bootstrap5",
|
||||
"social_django",
|
||||
"django_extensions",
|
||||
"bootstrap_pagination",
|
||||
'tjdests.apps.authentication',
|
||||
'tjdests.apps.destinations',
|
||||
"tjdests.apps.authentication",
|
||||
"tjdests.apps.destinations",
|
||||
"tjdests.apps.profile",
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
"django.middleware.security.SecurityMiddleware",
|
||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"django.middleware.csrf.CsrfViewMiddleware",
|
||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||
"django.contrib.messages.middleware.MessageMiddleware",
|
||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'tjdests.urls'
|
||||
ROOT_URLCONF = "tjdests.urls"
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [BASE_DIR / 'templates']
|
||||
,
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
'tjdests.apps.context_processors.settings_renderer',
|
||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||
"DIRS": [BASE_DIR / "templates"],
|
||||
"APP_DIRS": True,
|
||||
"OPTIONS": {
|
||||
"context_processors": [
|
||||
"django.template.context_processors.debug",
|
||||
"django.template.context_processors.request",
|
||||
"django.contrib.auth.context_processors.auth",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
"tjdests.apps.context_processors.settings_renderer",
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'tjdests.wsgi.application'
|
||||
WSGI_APPLICATION = "tjdests.wsgi.application"
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': BASE_DIR / 'db.sqlite3',
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.sqlite3",
|
||||
"NAME": BASE_DIR / "db.sqlite3",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,22 +96,25 @@ DATABASES = {
|
|||
|
||||
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"
|
||||
|
||||
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_ION_KEY = ""
|
||||
|
@ -122,9 +124,9 @@ SOCIAL_AUTH_ION_SECRET = ""
|
|||
# Internationalization
|
||||
# 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
|
||||
|
||||
|
@ -136,14 +138,14 @@ USE_TZ = True
|
|||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/3.2/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
STATIC_URL = "/static/"
|
||||
STATIC_ROOT = os.path.join(BASE_DIR, "serve/")
|
||||
STATICFILES_DIRS = (os.path.join(BASE_DIR, "static/"),)
|
||||
|
||||
# Default primary key field type
|
||||
# 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"
|
||||
LOGOUT_REDIRECT_URL = "authentication:index"
|
||||
|
|
|
@ -10,7 +10,7 @@ DEBUG = True
|
|||
ALLOWED_HOSTS = []
|
||||
|
||||
# secret
|
||||
SECRET_KEY = 'supersecret'
|
||||
SECRET_KEY = "supersecret"
|
||||
|
||||
# OAuth
|
||||
SOCIAL_AUTH_ION_KEY = "ionkey"
|
||||
|
|
|
@ -14,12 +14,15 @@ Including another URLconf
|
|||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||
"""
|
||||
from django.contrib import admin
|
||||
from django.urls import path, include
|
||||
from django.urls import include, path
|
||||
|
||||
urlpatterns = [
|
||||
path('djangoadmin/', admin.site.urls),
|
||||
path("djangoadmin/", admin.site.urls),
|
||||
path("", include("tjdests.apps.authentication.urls", namespace="authentication")),
|
||||
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")),
|
||||
]
|
||||
|
|
|
@ -11,6 +11,6 @@ import os
|
|||
|
||||
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()
|
||||
|
|
Loading…
Reference in New Issue
Block a user