mirror of
https://github.com/etnguyen03/tjdests.git
synced 2025-04-03 19:20:16 -04:00
Initial commit
This commit is contained in:
commit
f1b3814c7f
121
.gitignore
vendored
Normal file
121
.gitignore
vendored
Normal file
|
@ -0,0 +1,121 @@
|
|||
# Django #
|
||||
*.log
|
||||
*.pot
|
||||
*.pyc
|
||||
__pycache__
|
||||
db.sqlite3
|
||||
media
|
||||
|
||||
# Backup files #
|
||||
*.bak
|
||||
|
||||
# If you are using PyCharm #
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/dictionaries
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.xml
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
*.iws /out/
|
||||
|
||||
# Python #
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# Distribution / packaging
|
||||
.Python build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
.pytest_cache/
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
.hypothesis/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# celery
|
||||
celerybeat-schedule.*
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
|
||||
# Sublime Text #
|
||||
*.tmlanguage.cache
|
||||
*.tmPreferences.cache
|
||||
*.stTheme.cache
|
||||
*.sublime-workspace
|
||||
*.sublime-project
|
||||
|
||||
# sftp configuration file
|
||||
sftp-config.json
|
||||
|
||||
# Package control specific files Package
|
||||
Control.last-run
|
||||
Control.ca-list
|
||||
Control.ca-bundle
|
||||
Control.system-ca-bundle
|
||||
GitHub.sublime-settings
|
||||
|
||||
# Visual Studio Code #
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
.history
|
||||
|
||||
tjdests/settings/secret.py
|
||||
/.idea/
|
||||
/tjdests/serve/
|
||||
secret.py
|
660
LICENSE.md
Normal file
660
LICENSE.md
Normal file
|
@ -0,0 +1,660 @@
|
|||
### GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
<https://fsf.org/>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this
|
||||
license document, but changing it is not allowed.
|
||||
|
||||
### Preamble
|
||||
|
||||
The GNU Affero General Public License is a free, copyleft license for
|
||||
software and other kinds of works, specifically designed to ensure
|
||||
cooperation with the community in the case of network server software.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
our General Public Licenses are intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains
|
||||
free software for all its users.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
Developers that use our General Public Licenses protect your rights
|
||||
with two steps: (1) assert copyright on the software, and (2) offer
|
||||
you this License which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
|
||||
A secondary benefit of defending all users' freedom is that
|
||||
improvements made in alternate versions of the program, if they
|
||||
receive widespread use, become available for other developers to
|
||||
incorporate. Many developers of free software are heartened and
|
||||
encouraged by the resulting cooperation. However, in the case of
|
||||
software used on network servers, this result may fail to come about.
|
||||
The GNU General Public License permits making a modified version and
|
||||
letting the public access it on a server without ever releasing its
|
||||
source code to the public.
|
||||
|
||||
The GNU Affero General Public License is designed specifically to
|
||||
ensure that, in such cases, the modified source code becomes available
|
||||
to the community. It requires the operator of a network server to
|
||||
provide the source code of the modified version running there to the
|
||||
users of that server. Therefore, public use of a modified version, on
|
||||
a publicly accessible server, gives the public access to the source
|
||||
code of the modified version.
|
||||
|
||||
An older license, called the Affero General Public License and
|
||||
published by Affero, was designed to accomplish similar goals. This is
|
||||
a different license, not a version of the Affero GPL, but Affero has
|
||||
released a new version of the Affero GPL which permits relicensing
|
||||
under this license.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
### TERMS AND CONDITIONS
|
||||
|
||||
#### 0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds
|
||||
of works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of
|
||||
an exact copy. The resulting work is called a "modified version" of
|
||||
the earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user
|
||||
through a computer network, with no transfer of a copy, is not
|
||||
conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices" to
|
||||
the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
#### 1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work for
|
||||
making modifications to it. "Object code" means any non-source form of
|
||||
a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users can
|
||||
regenerate automatically from other parts of the Corresponding Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that same
|
||||
work.
|
||||
|
||||
#### 2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not convey,
|
||||
without conditions so long as your license otherwise remains in force.
|
||||
You may convey covered works to others for the sole purpose of having
|
||||
them make modifications exclusively for you, or provide you with
|
||||
facilities for running those works, provided that you comply with the
|
||||
terms of this License in conveying all material for which you do not
|
||||
control copyright. Those thus making or running the covered works for
|
||||
you must do so exclusively on your behalf, under your direction and
|
||||
control, on terms that prohibit them from making any copies of your
|
||||
copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under the
|
||||
conditions stated below. Sublicensing is not allowed; section 10 makes
|
||||
it unnecessary.
|
||||
|
||||
#### 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such
|
||||
circumvention is effected by exercising rights under this License with
|
||||
respect to the covered work, and you disclaim any intention to limit
|
||||
operation or modification of the work as a means of enforcing, against
|
||||
the work's users, your or third parties' legal rights to forbid
|
||||
circumvention of technological measures.
|
||||
|
||||
#### 4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
#### 5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these
|
||||
conditions:
|
||||
|
||||
- a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
- b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under
|
||||
section 7. This requirement modifies the requirement in section 4
|
||||
to "keep intact all notices".
|
||||
- c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
- d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
#### 6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms of
|
||||
sections 4 and 5, provided that you also convey the machine-readable
|
||||
Corresponding Source under the terms of this License, in one of these
|
||||
ways:
|
||||
|
||||
- a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
- b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the Corresponding
|
||||
Source from a network server at no charge.
|
||||
- c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
- d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
- e) Convey the object code using peer-to-peer transmission,
|
||||
provided you inform other peers where the object code and
|
||||
Corresponding Source of the work are being offered to the general
|
||||
public at no charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal,
|
||||
family, or household purposes, or (2) anything designed or sold for
|
||||
incorporation into a dwelling. In determining whether a product is a
|
||||
consumer product, doubtful cases shall be resolved in favor of
|
||||
coverage. For a particular product received by a particular user,
|
||||
"normally used" refers to a typical or common use of that class of
|
||||
product, regardless of the status of the particular user or of the way
|
||||
in which the particular user actually uses, or expects or is expected
|
||||
to use, the product. A product is a consumer product regardless of
|
||||
whether the product has substantial commercial, industrial or
|
||||
non-consumer uses, unless such uses represent the only significant
|
||||
mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to
|
||||
install and execute modified versions of a covered work in that User
|
||||
Product from a modified version of its Corresponding Source. The
|
||||
information must suffice to ensure that the continued functioning of
|
||||
the modified object code is in no case prevented or interfered with
|
||||
solely because modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or
|
||||
updates for a work that has been modified or installed by the
|
||||
recipient, or for the User Product in which it has been modified or
|
||||
installed. Access to a network may be denied when the modification
|
||||
itself materially and adversely affects the operation of the network
|
||||
or violates the rules and protocols for communication across the
|
||||
network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
#### 7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders
|
||||
of that material) supplement the terms of this License with terms:
|
||||
|
||||
- a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
- b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
- c) Prohibiting misrepresentation of the origin of that material,
|
||||
or requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
- d) Limiting the use for publicity purposes of names of licensors
|
||||
or authors of the material; or
|
||||
- e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
- f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions
|
||||
of it) with contractual assumptions of liability to the recipient,
|
||||
for any liability that these contractual assumptions directly
|
||||
impose on those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions; the
|
||||
above requirements apply either way.
|
||||
|
||||
#### 8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your license
|
||||
from a particular copyright holder is reinstated (a) provisionally,
|
||||
unless and until the copyright holder explicitly and finally
|
||||
terminates your license, and (b) permanently, if the copyright holder
|
||||
fails to notify you of the violation by some reasonable means prior to
|
||||
60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
#### 9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or run
|
||||
a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
#### 10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
#### 11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims owned
|
||||
or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within the
|
||||
scope of its coverage, prohibits the exercise of, or is conditioned on
|
||||
the non-exercise of one or more of the rights that are specifically
|
||||
granted under this License. You may not convey a covered work if you
|
||||
are a party to an arrangement with a third party that is in the
|
||||
business of distributing software, under which you make payment to the
|
||||
third party based on the extent of your activity of conveying the
|
||||
work, and under which the third party grants, to any of the parties
|
||||
who would receive the covered work from you, a discriminatory patent
|
||||
license (a) in connection with copies of the covered work conveyed by
|
||||
you (or copies made from those copies), or (b) primarily for and in
|
||||
connection with specific products or compilations that contain the
|
||||
covered work, unless you entered into that arrangement, or that patent
|
||||
license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
#### 12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under
|
||||
this License and any other pertinent obligations, then as a
|
||||
consequence you may not convey it at all. For example, if you agree to
|
||||
terms that obligate you to collect a royalty for further conveying
|
||||
from those to whom you convey the Program, the only way you could
|
||||
satisfy both those terms and this License would be to refrain entirely
|
||||
from conveying the Program.
|
||||
|
||||
#### 13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, if you modify the
|
||||
Program, your modified version must prominently offer all users
|
||||
interacting with it remotely through a computer network (if your
|
||||
version supports such interaction) an opportunity to receive the
|
||||
Corresponding Source of your version by providing access to the
|
||||
Corresponding Source from a network server at no charge, through some
|
||||
standard or customary means of facilitating copying of software. This
|
||||
Corresponding Source shall include the Corresponding Source for any
|
||||
work covered by version 3 of the GNU General Public License that is
|
||||
incorporated pursuant to the following paragraph.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the work with which it is combined will remain governed by version
|
||||
3 of the GNU General Public License.
|
||||
|
||||
#### 14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Affero General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies that a certain numbered version of the GNU Affero General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU Affero General Public License, you may choose any version ever
|
||||
published by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future versions
|
||||
of the GNU Affero General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
#### 15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT
|
||||
WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
|
||||
PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
|
||||
DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
|
||||
CORRECTION.
|
||||
|
||||
#### 16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR
|
||||
CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
|
||||
ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT
|
||||
NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR
|
||||
LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM
|
||||
TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER
|
||||
PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
#### 17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
### How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these
|
||||
terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest to
|
||||
attach them to the start of each source file to most effectively state
|
||||
the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper
|
||||
mail.
|
||||
|
||||
If your software can interact with users remotely through a computer
|
||||
network, you should also make sure that it provides a way for users to
|
||||
get its source. For example, if your program is a web application, its
|
||||
interface could display a "Source" link that leads users to an archive
|
||||
of the code. There are many ways you could offer source, and different
|
||||
solutions will be better for different programs; see section 13 for
|
||||
the specific requirements.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. For more information on this, and how to apply and follow
|
||||
the GNU AGPL, see <https://www.gnu.org/licenses/>.
|
29
Pipfile
Normal file
29
Pipfile
Normal file
|
@ -0,0 +1,29 @@
|
|||
[[source]]
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
django = "~=3.2"
|
||||
social-auth-app-django = "~=4.0.0"
|
||||
whitenoise = "~=5.2"
|
||||
django-crispy-forms = "~=1.11.2"
|
||||
crispy-bootstrap5 = "~=0.3.1"
|
||||
django-extensions = "~=3.1.2"
|
||||
ipython = "~=7.22.0"
|
||||
django-bootstrap-pagination = "~=1.7.1"
|
||||
|
||||
[dev-packages]
|
||||
autopep8 = "~=1.5.6"
|
||||
black = "==20.8b1"
|
||||
coverage = "~=5.5"
|
||||
django-stubs = "~=1.7.0"
|
||||
flake8 = "~=3.9.0"
|
||||
isort = "~=5.8.0"
|
||||
mypy = "~=0.812"
|
||||
pylint = "~=2.7.4"
|
||||
pylint-django = "~=2.4.2"
|
||||
typed-ast = "~=1.4.2" # Required by black, but Pipenv doesn't pull it in correctly on 3.8
|
||||
|
||||
[requires]
|
||||
python_version = "3.9"
|
734
Pipfile.lock
generated
Normal file
734
Pipfile.lock
generated
Normal file
|
@ -0,0 +1,734 @@
|
|||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "18a19c14dc35df0516a99446a4e14571ea626b0eae6ff13b342cce4550ce15c3"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.9"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"asgiref": {
|
||||
"hashes": [
|
||||
"sha256:92906c611ce6c967347bbfea733f13d6313901d54dcca88195eaeb52b2a8e8ee",
|
||||
"sha256:d1216dfbdfb63826470995d31caed36225dcaf34f182e0fa257a4dd9e86f1b78"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.3.4"
|
||||
},
|
||||
"backcall": {
|
||||
"hashes": [
|
||||
"sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e",
|
||||
"sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"
|
||||
],
|
||||
"version": "==0.2.0"
|
||||
},
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
"sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c",
|
||||
"sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"
|
||||
],
|
||||
"version": "==2020.12.5"
|
||||
},
|
||||
"cffi": {
|
||||
"hashes": [
|
||||
"sha256:005a36f41773e148deac64b08f233873a4d0c18b053d37da83f6af4d9087b813",
|
||||
"sha256:0857f0ae312d855239a55c81ef453ee8fd24136eaba8e87a2eceba644c0d4c06",
|
||||
"sha256:1071534bbbf8cbb31b498d5d9db0f274f2f7a865adca4ae429e147ba40f73dea",
|
||||
"sha256:158d0d15119b4b7ff6b926536763dc0714313aa59e320ddf787502c70c4d4bee",
|
||||
"sha256:1f436816fc868b098b0d63b8920de7d208c90a67212546d02f84fe78a9c26396",
|
||||
"sha256:2894f2df484ff56d717bead0a5c2abb6b9d2bf26d6960c4604d5c48bbc30ee73",
|
||||
"sha256:29314480e958fd8aab22e4a58b355b629c59bf5f2ac2492b61e3dc06d8c7a315",
|
||||
"sha256:34eff4b97f3d982fb93e2831e6750127d1355a923ebaeeb565407b3d2f8d41a1",
|
||||
"sha256:35f27e6eb43380fa080dccf676dece30bef72e4a67617ffda586641cd4508d49",
|
||||
"sha256:3d3dd4c9e559eb172ecf00a2a7517e97d1e96de2a5e610bd9b68cea3925b4892",
|
||||
"sha256:43e0b9d9e2c9e5d152946b9c5fe062c151614b262fda2e7b201204de0b99e482",
|
||||
"sha256:48e1c69bbacfc3d932221851b39d49e81567a4d4aac3b21258d9c24578280058",
|
||||
"sha256:51182f8927c5af975fece87b1b369f722c570fe169f9880764b1ee3bca8347b5",
|
||||
"sha256:58e3f59d583d413809d60779492342801d6e82fefb89c86a38e040c16883be53",
|
||||
"sha256:5de7970188bb46b7bf9858eb6890aad302577a5f6f75091fd7cdd3ef13ef3045",
|
||||
"sha256:65fa59693c62cf06e45ddbb822165394a288edce9e276647f0046e1ec26920f3",
|
||||
"sha256:69e395c24fc60aad6bb4fa7e583698ea6cc684648e1ffb7fe85e3c1ca131a7d5",
|
||||
"sha256:6c97d7350133666fbb5cf4abdc1178c812cb205dc6f41d174a7b0f18fb93337e",
|
||||
"sha256:6e4714cc64f474e4d6e37cfff31a814b509a35cb17de4fb1999907575684479c",
|
||||
"sha256:72d8d3ef52c208ee1c7b2e341f7d71c6fd3157138abf1a95166e6165dd5d4369",
|
||||
"sha256:8ae6299f6c68de06f136f1f9e69458eae58f1dacf10af5c17353eae03aa0d827",
|
||||
"sha256:8b198cec6c72df5289c05b05b8b0969819783f9418e0409865dac47288d2a053",
|
||||
"sha256:99cd03ae7988a93dd00bcd9d0b75e1f6c426063d6f03d2f90b89e29b25b82dfa",
|
||||
"sha256:9cf8022fb8d07a97c178b02327b284521c7708d7c71a9c9c355c178ac4bbd3d4",
|
||||
"sha256:9de2e279153a443c656f2defd67769e6d1e4163952b3c622dcea5b08a6405322",
|
||||
"sha256:9e93e79c2551ff263400e1e4be085a1210e12073a31c2011dbbda14bda0c6132",
|
||||
"sha256:9ff227395193126d82e60319a673a037d5de84633f11279e336f9c0f189ecc62",
|
||||
"sha256:a465da611f6fa124963b91bf432d960a555563efe4ed1cc403ba5077b15370aa",
|
||||
"sha256:ad17025d226ee5beec591b52800c11680fca3df50b8b29fe51d882576e039ee0",
|
||||
"sha256:afb29c1ba2e5a3736f1c301d9d0abe3ec8b86957d04ddfa9d7a6a42b9367e396",
|
||||
"sha256:b85eb46a81787c50650f2392b9b4ef23e1f126313b9e0e9013b35c15e4288e2e",
|
||||
"sha256:bb89f306e5da99f4d922728ddcd6f7fcebb3241fc40edebcb7284d7514741991",
|
||||
"sha256:cbde590d4faaa07c72bf979734738f328d239913ba3e043b1e98fe9a39f8b2b6",
|
||||
"sha256:cd2868886d547469123fadc46eac7ea5253ea7fcb139f12e1dfc2bbd406427d1",
|
||||
"sha256:d42b11d692e11b6634f7613ad8df5d6d5f8875f5d48939520d351007b3c13406",
|
||||
"sha256:f2d45f97ab6bb54753eab54fffe75aaf3de4ff2341c9daee1987ee1837636f1d",
|
||||
"sha256:fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c"
|
||||
],
|
||||
"version": "==1.14.5"
|
||||
},
|
||||
"chardet": {
|
||||
"hashes": [
|
||||
"sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
|
||||
"sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==4.0.0"
|
||||
},
|
||||
"crispy-bootstrap5": {
|
||||
"hashes": [
|
||||
"sha256:79e518fdf4d94e64ec2f1abfd85eed348724e9cb432cec3dfaf531177603d17d",
|
||||
"sha256:ec62daf8d50271031c53a484b43e10bccc0cebde34f253a3c784964658df5826"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.3.1"
|
||||
},
|
||||
"cryptography": {
|
||||
"hashes": [
|
||||
"sha256:0f1212a66329c80d68aeeb39b8a16d54ef57071bf22ff4e521657b27372e327d",
|
||||
"sha256:1e056c28420c072c5e3cb36e2b23ee55e260cb04eee08f702e0edfec3fb51959",
|
||||
"sha256:240f5c21aef0b73f40bb9f78d2caff73186700bf1bc6b94285699aff98cc16c6",
|
||||
"sha256:26965837447f9c82f1855e0bc8bc4fb910240b6e0d16a664bb722df3b5b06873",
|
||||
"sha256:37340614f8a5d2fb9aeea67fd159bfe4f5f4ed535b1090ce8ec428b2f15a11f2",
|
||||
"sha256:3d10de8116d25649631977cb37da6cbdd2d6fa0e0281d014a5b7d337255ca713",
|
||||
"sha256:3d8427734c781ea5f1b41d6589c293089704d4759e34597dce91014ac125aad1",
|
||||
"sha256:7ec5d3b029f5fa2b179325908b9cd93db28ab7b85bb6c1db56b10e0b54235177",
|
||||
"sha256:8e56e16617872b0957d1c9742a3f94b43533447fd78321514abbe7db216aa250",
|
||||
"sha256:de4e5f7f68220d92b7637fc99847475b59154b7a1b3868fb7385337af54ac9ca",
|
||||
"sha256:eb8cc2afe8b05acbd84a43905832ec78e7b3873fb124ca190f574dca7389a87d",
|
||||
"sha256:ee77aa129f481be46f8d92a1a7db57269a2f23052d5f2433b4621bb457081cc9"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.4.7"
|
||||
},
|
||||
"decorator": {
|
||||
"hashes": [
|
||||
"sha256:6f201a6c4dac3d187352661f508b9364ec8091217442c9478f1f83c003a0f060",
|
||||
"sha256:945d84890bb20cc4a2f4a31fc4311c0c473af65ea318617f13a7257c9a58bc98"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==5.0.7"
|
||||
},
|
||||
"defusedxml": {
|
||||
"hashes": [
|
||||
"sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69",
|
||||
"sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==0.7.1"
|
||||
},
|
||||
"django": {
|
||||
"hashes": [
|
||||
"sha256:0604e84c4fb698a5e53e5857b5aea945b2f19a18f25f10b8748dbdf935788927",
|
||||
"sha256:21f0f9643722675976004eb683c55d33c05486f94506672df3d6a141546f389d"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.2"
|
||||
},
|
||||
"django-bootstrap-pagination": {
|
||||
"hashes": [
|
||||
"sha256:47e742679cf109e12f10ae09d5263433f94440818cf7b023e90a3f5252849639",
|
||||
"sha256:69d826d92217325611cb86e49944d8261e3c92eaa4deafea5a605d79fd363883"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.7.1"
|
||||
},
|
||||
"django-crispy-forms": {
|
||||
"hashes": [
|
||||
"sha256:3db71ab06d17ec9d0195c086d3ad454da300ac268752ac3a4f63d72f7a490254",
|
||||
"sha256:88efa857ce6111bd696cc4f74057539a3456102fe9c3a3ece8868e1e4579e70a"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.11.2"
|
||||
},
|
||||
"django-extensions": {
|
||||
"hashes": [
|
||||
"sha256:081828e985485662f62a22340c1506e37989d14b927652079a5b7cd84a82368b",
|
||||
"sha256:17f85f4dcdd5eea09b8c4f0bad8f0370bf2db6d03e61b431fa7103fee29888de"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.1.2"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
"sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6",
|
||||
"sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.10"
|
||||
},
|
||||
"ipython": {
|
||||
"hashes": [
|
||||
"sha256:9c900332d4c5a6de534b4befeeb7de44ad0cc42e8327fa41b7685abde58cec74",
|
||||
"sha256:c0ce02dfaa5f854809ab7413c601c4543846d9da81010258ecdab299b542d199"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==7.22.0"
|
||||
},
|
||||
"ipython-genutils": {
|
||||
"hashes": [
|
||||
"sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8",
|
||||
"sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"
|
||||
],
|
||||
"version": "==0.2.0"
|
||||
},
|
||||
"jedi": {
|
||||
"hashes": [
|
||||
"sha256:18456d83f65f400ab0c2d3319e48520420ef43b23a086fdc05dff34132f0fb93",
|
||||
"sha256:92550a404bad8afed881a137ec9a461fed49eca661414be45059329614ed0707"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==0.18.0"
|
||||
},
|
||||
"oauthlib": {
|
||||
"hashes": [
|
||||
"sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889",
|
||||
"sha256:df884cd6cbe20e32633f1db1072e9356f53638e4361bef4e8b03c9127c9328ea"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==3.1.0"
|
||||
},
|
||||
"parso": {
|
||||
"hashes": [
|
||||
"sha256:12b83492c6239ce32ff5eed6d3639d6a536170723c6f3f1506869f1ace413398",
|
||||
"sha256:a8c4922db71e4fdb90e0d0bc6e50f9b273d3397925e5e60a717e719201778d22"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==0.8.2"
|
||||
},
|
||||
"pexpect": {
|
||||
"hashes": [
|
||||
"sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937",
|
||||
"sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"
|
||||
],
|
||||
"markers": "sys_platform != 'win32'",
|
||||
"version": "==4.8.0"
|
||||
},
|
||||
"pickleshare": {
|
||||
"hashes": [
|
||||
"sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca",
|
||||
"sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"
|
||||
],
|
||||
"version": "==0.7.5"
|
||||
},
|
||||
"prompt-toolkit": {
|
||||
"hashes": [
|
||||
"sha256:bf00f22079f5fadc949f42ae8ff7f05702826a97059ffcc6281036ad40ac6f04",
|
||||
"sha256:e1b4f11b9336a28fa11810bc623c357420f69dfdb6d2dac41ca2c21a55c033bc"
|
||||
],
|
||||
"markers": "python_full_version >= '3.6.1'",
|
||||
"version": "==3.0.18"
|
||||
},
|
||||
"ptyprocess": {
|
||||
"hashes": [
|
||||
"sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35",
|
||||
"sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"
|
||||
],
|
||||
"version": "==0.7.0"
|
||||
},
|
||||
"pycparser": {
|
||||
"hashes": [
|
||||
"sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0",
|
||||
"sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.20"
|
||||
},
|
||||
"pygments": {
|
||||
"hashes": [
|
||||
"sha256:2656e1a6edcdabf4275f9a3640db59fd5de107d88e8663c5d4e9a0fa62f77f94",
|
||||
"sha256:534ef71d539ae97d4c3a4cf7d6f110f214b0e687e92f9cb9d2a3b0d3101289c8"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==2.8.1"
|
||||
},
|
||||
"pyjwt": {
|
||||
"hashes": [
|
||||
"sha256:a5c70a06e1f33d81ef25eecd50d50bd30e34de1ca8b2b9fa3fe0daaabcf69bf7",
|
||||
"sha256:b70b15f89dc69b993d8a8d32c299032d5355c82f9b5b7e851d1a6d706dffe847"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.0.1"
|
||||
},
|
||||
"python3-openid": {
|
||||
"hashes": [
|
||||
"sha256:33fbf6928f401e0b790151ed2b5290b02545e8775f982485205a066f874aaeaf",
|
||||
"sha256:6626f771e0417486701e0b4daff762e7212e820ca5b29fcc0d05f6f8736dfa6b"
|
||||
],
|
||||
"version": "==3.2.0"
|
||||
},
|
||||
"pytz": {
|
||||
"hashes": [
|
||||
"sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da",
|
||||
"sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"
|
||||
],
|
||||
"version": "==2021.1"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
"sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804",
|
||||
"sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==2.25.1"
|
||||
},
|
||||
"requests-oauthlib": {
|
||||
"hashes": [
|
||||
"sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d",
|
||||
"sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a",
|
||||
"sha256:fa6c47b933f01060936d87ae9327fead68768b69c6c9ea2109c48be30f2d4dbc"
|
||||
],
|
||||
"version": "==1.3.0"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259",
|
||||
"sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==1.15.0"
|
||||
},
|
||||
"social-auth-app-django": {
|
||||
"hashes": [
|
||||
"sha256:2c69e57df0b30c9c1823519c5f1992cbe4f3f98fdc7d95c840e091a752708840",
|
||||
"sha256:567ad0e028311541d7dfed51d3bf2c60440a6fd236d5d4d06c5a618b3d6c57c5",
|
||||
"sha256:df5212370bd250108987c4748419a1a1d0cec750878856c2644c36aaa0fd3e58"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.0.0"
|
||||
},
|
||||
"social-auth-core": {
|
||||
"hashes": [
|
||||
"sha256:5ab43b3b15dce5f059db69cc3082c216574739f0edbc98629c8c6e8769c67eb4",
|
||||
"sha256:983b53167ac56e7ba4909db555602a6e7a98c97ca47183bb222eb85ba627bf2b"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==4.1.0"
|
||||
},
|
||||
"sqlparse": {
|
||||
"hashes": [
|
||||
"sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0",
|
||||
"sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==0.4.1"
|
||||
},
|
||||
"traitlets": {
|
||||
"hashes": [
|
||||
"sha256:178f4ce988f69189f7e523337a3e11d91c786ded9360174a3d9ca83e79bc5396",
|
||||
"sha256:69ff3f9d5351f31a7ad80443c2674b7099df13cc41fc5fa6e2f6d3b0330b0426"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==5.0.5"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df",
|
||||
"sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
|
||||
"version": "==1.26.4"
|
||||
},
|
||||
"wcwidth": {
|
||||
"hashes": [
|
||||
"sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784",
|
||||
"sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"
|
||||
],
|
||||
"version": "==0.2.5"
|
||||
},
|
||||
"whitenoise": {
|
||||
"hashes": [
|
||||
"sha256:05ce0be39ad85740a78750c86a93485c40f08ad8c62a6006de0233765996e5c7",
|
||||
"sha256:05d00198c777028d72d8b0bbd234db605ef6d60e9410125124002518a48e515d"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==5.2.0"
|
||||
}
|
||||
},
|
||||
"develop": {
|
||||
"appdirs": {
|
||||
"hashes": [
|
||||
"sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41",
|
||||
"sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"
|
||||
],
|
||||
"version": "==1.4.4"
|
||||
},
|
||||
"asgiref": {
|
||||
"hashes": [
|
||||
"sha256:92906c611ce6c967347bbfea733f13d6313901d54dcca88195eaeb52b2a8e8ee",
|
||||
"sha256:d1216dfbdfb63826470995d31caed36225dcaf34f182e0fa257a4dd9e86f1b78"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.3.4"
|
||||
},
|
||||
"astroid": {
|
||||
"hashes": [
|
||||
"sha256:ad63b8552c70939568966811a088ef0bc880f99a24a00834abd0e3681b514f91",
|
||||
"sha256:bea3f32799fbb8581f58431c12591bc20ce11cbc90ad82e2ea5717d94f2080d5"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.5.3"
|
||||
},
|
||||
"autopep8": {
|
||||
"hashes": [
|
||||
"sha256:5454e6e9a3d02aae38f866eec0d9a7de4ab9f93c10a273fb0340f3d6d09f7514",
|
||||
"sha256:f01b06a6808bc31698db907761e5890eb2295e287af53f6693b39ce55454034a"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.5.6"
|
||||
},
|
||||
"black": {
|
||||
"hashes": [
|
||||
"sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==20.8b1"
|
||||
},
|
||||
"click": {
|
||||
"hashes": [
|
||||
"sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a",
|
||||
"sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==7.1.2"
|
||||
},
|
||||
"coverage": {
|
||||
"hashes": [
|
||||
"sha256:004d1880bed2d97151facef49f08e255a20ceb6f9432df75f4eef018fdd5a78c",
|
||||
"sha256:01d84219b5cdbfc8122223b39a954820929497a1cb1422824bb86b07b74594b6",
|
||||
"sha256:040af6c32813fa3eae5305d53f18875bedd079960822ef8ec067a66dd8afcd45",
|
||||
"sha256:06191eb60f8d8a5bc046f3799f8a07a2d7aefb9504b0209aff0b47298333302a",
|
||||
"sha256:13034c4409db851670bc9acd836243aeee299949bd5673e11844befcb0149f03",
|
||||
"sha256:13c4ee887eca0f4c5a247b75398d4114c37882658300e153113dafb1d76de529",
|
||||
"sha256:184a47bbe0aa6400ed2d41d8e9ed868b8205046518c52464fde713ea06e3a74a",
|
||||
"sha256:18ba8bbede96a2c3dde7b868de9dcbd55670690af0988713f0603f037848418a",
|
||||
"sha256:1aa846f56c3d49205c952d8318e76ccc2ae23303351d9270ab220004c580cfe2",
|
||||
"sha256:217658ec7187497e3f3ebd901afdca1af062b42cfe3e0dafea4cced3983739f6",
|
||||
"sha256:24d4a7de75446be83244eabbff746d66b9240ae020ced65d060815fac3423759",
|
||||
"sha256:2910f4d36a6a9b4214bb7038d537f015346f413a975d57ca6b43bf23d6563b53",
|
||||
"sha256:2949cad1c5208b8298d5686d5a85b66aae46d73eec2c3e08c817dd3513e5848a",
|
||||
"sha256:2a3859cb82dcbda1cfd3e6f71c27081d18aa251d20a17d87d26d4cd216fb0af4",
|
||||
"sha256:2cafbbb3af0733db200c9b5f798d18953b1a304d3f86a938367de1567f4b5bff",
|
||||
"sha256:2e0d881ad471768bf6e6c2bf905d183543f10098e3b3640fc029509530091502",
|
||||
"sha256:30c77c1dc9f253283e34c27935fded5015f7d1abe83bc7821680ac444eaf7793",
|
||||
"sha256:3487286bc29a5aa4b93a072e9592f22254291ce96a9fbc5251f566b6b7343cdb",
|
||||
"sha256:372da284cfd642d8e08ef606917846fa2ee350f64994bebfbd3afb0040436905",
|
||||
"sha256:41179b8a845742d1eb60449bdb2992196e211341818565abded11cfa90efb821",
|
||||
"sha256:44d654437b8ddd9eee7d1eaee28b7219bec228520ff809af170488fd2fed3e2b",
|
||||
"sha256:4a7697d8cb0f27399b0e393c0b90f0f1e40c82023ea4d45d22bce7032a5d7b81",
|
||||
"sha256:51cb9476a3987c8967ebab3f0fe144819781fca264f57f89760037a2ea191cb0",
|
||||
"sha256:52596d3d0e8bdf3af43db3e9ba8dcdaac724ba7b5ca3f6358529d56f7a166f8b",
|
||||
"sha256:53194af30d5bad77fcba80e23a1441c71abfb3e01192034f8246e0d8f99528f3",
|
||||
"sha256:5fec2d43a2cc6965edc0bb9e83e1e4b557f76f843a77a2496cbe719583ce8184",
|
||||
"sha256:6c90e11318f0d3c436a42409f2749ee1a115cd8b067d7f14c148f1ce5574d701",
|
||||
"sha256:74d881fc777ebb11c63736622b60cb9e4aee5cace591ce274fb69e582a12a61a",
|
||||
"sha256:7501140f755b725495941b43347ba8a2777407fc7f250d4f5a7d2a1050ba8e82",
|
||||
"sha256:796c9c3c79747146ebd278dbe1e5c5c05dd6b10cc3bcb8389dfdf844f3ead638",
|
||||
"sha256:869a64f53488f40fa5b5b9dcb9e9b2962a66a87dab37790f3fcfb5144b996ef5",
|
||||
"sha256:8963a499849a1fc54b35b1c9f162f4108017b2e6db2c46c1bed93a72262ed083",
|
||||
"sha256:8d0a0725ad7c1a0bcd8d1b437e191107d457e2ec1084b9f190630a4fb1af78e6",
|
||||
"sha256:900fbf7759501bc7807fd6638c947d7a831fc9fdf742dc10f02956ff7220fa90",
|
||||
"sha256:92b017ce34b68a7d67bd6d117e6d443a9bf63a2ecf8567bb3d8c6c7bc5014465",
|
||||
"sha256:970284a88b99673ccb2e4e334cfb38a10aab7cd44f7457564d11898a74b62d0a",
|
||||
"sha256:972c85d205b51e30e59525694670de6a8a89691186012535f9d7dbaa230e42c3",
|
||||
"sha256:9a1ef3b66e38ef8618ce5fdc7bea3d9f45f3624e2a66295eea5e57966c85909e",
|
||||
"sha256:af0e781009aaf59e25c5a678122391cb0f345ac0ec272c7961dc5455e1c40066",
|
||||
"sha256:b6d534e4b2ab35c9f93f46229363e17f63c53ad01330df9f2d6bd1187e5eaacf",
|
||||
"sha256:b7895207b4c843c76a25ab8c1e866261bcfe27bfaa20c192de5190121770672b",
|
||||
"sha256:c0891a6a97b09c1f3e073a890514d5012eb256845c451bd48f7968ef939bf4ae",
|
||||
"sha256:c2723d347ab06e7ddad1a58b2a821218239249a9e4365eaff6649d31180c1669",
|
||||
"sha256:d1f8bf7b90ba55699b3a5e44930e93ff0189aa27186e96071fac7dd0d06a1873",
|
||||
"sha256:d1f9ce122f83b2305592c11d64f181b87153fc2c2bbd3bb4a3dde8303cfb1a6b",
|
||||
"sha256:d314ed732c25d29775e84a960c3c60808b682c08d86602ec2c3008e1202e3bb6",
|
||||
"sha256:d636598c8305e1f90b439dbf4f66437de4a5e3c31fdf47ad29542478c8508bbb",
|
||||
"sha256:deee1077aae10d8fa88cb02c845cfba9b62c55e1183f52f6ae6a2df6a2187160",
|
||||
"sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c",
|
||||
"sha256:f030f8873312a16414c0d8e1a1ddff2d3235655a2174e3648b4fa66b3f2f1079",
|
||||
"sha256:f0b278ce10936db1a37e6954e15a3730bea96a0997c26d7fee88e6c396c2086d",
|
||||
"sha256:f11642dddbb0253cc8853254301b51390ba0081750a8ac03f20ea8103f0c56b6"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==5.5"
|
||||
},
|
||||
"django": {
|
||||
"hashes": [
|
||||
"sha256:0604e84c4fb698a5e53e5857b5aea945b2f19a18f25f10b8748dbdf935788927",
|
||||
"sha256:21f0f9643722675976004eb683c55d33c05486f94506672df3d6a141546f389d"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.2"
|
||||
},
|
||||
"django-stubs": {
|
||||
"hashes": [
|
||||
"sha256:30a7d99c694acf79c5d93d69a5a8e4b54d2a8c11dd672aa869006789e2189fa6",
|
||||
"sha256:ddd190aca5b9adb4d30760d5c64f67cb3658703f5f42c3bb0c2c71ff4d752c39"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.7.0"
|
||||
},
|
||||
"flake8": {
|
||||
"hashes": [
|
||||
"sha256:1aa8990be1e689d96c745c5682b687ea49f2e05a443aff1f8251092b0014e378",
|
||||
"sha256:3b9f848952dddccf635be78098ca75010f073bfe14d2c6bda867154bea728d2a"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.9.1"
|
||||
},
|
||||
"isort": {
|
||||
"hashes": [
|
||||
"sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6",
|
||||
"sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==5.8.0"
|
||||
},
|
||||
"lazy-object-proxy": {
|
||||
"hashes": [
|
||||
"sha256:17e0967ba374fc24141738c69736da90e94419338fd4c7c7bef01ee26b339653",
|
||||
"sha256:1fee665d2638491f4d6e55bd483e15ef21f6c8c2095f235fef72601021e64f61",
|
||||
"sha256:22ddd618cefe54305df49e4c069fa65715be4ad0e78e8d252a33debf00f6ede2",
|
||||
"sha256:24a5045889cc2729033b3e604d496c2b6f588c754f7a62027ad4437a7ecc4837",
|
||||
"sha256:410283732af311b51b837894fa2f24f2c0039aa7f220135192b38fcc42bd43d3",
|
||||
"sha256:4732c765372bd78a2d6b2150a6e99d00a78ec963375f236979c0626b97ed8e43",
|
||||
"sha256:489000d368377571c6f982fba6497f2aa13c6d1facc40660963da62f5c379726",
|
||||
"sha256:4f60460e9f1eb632584c9685bccea152f4ac2130e299784dbaf9fae9f49891b3",
|
||||
"sha256:5743a5ab42ae40caa8421b320ebf3a998f89c85cdc8376d6b2e00bd12bd1b587",
|
||||
"sha256:85fb7608121fd5621cc4377a8961d0b32ccf84a7285b4f1d21988b2eae2868e8",
|
||||
"sha256:9698110e36e2df951c7c36b6729e96429c9c32b3331989ef19976592c5f3c77a",
|
||||
"sha256:9d397bf41caad3f489e10774667310d73cb9c4258e9aed94b9ec734b34b495fd",
|
||||
"sha256:b579f8acbf2bdd9ea200b1d5dea36abd93cabf56cf626ab9c744a432e15c815f",
|
||||
"sha256:b865b01a2e7f96db0c5d12cfea590f98d8c5ba64ad222300d93ce6ff9138bcad",
|
||||
"sha256:bf34e368e8dd976423396555078def5cfc3039ebc6fc06d1ae2c5a65eebbcde4",
|
||||
"sha256:c6938967f8528b3668622a9ed3b31d145fab161a32f5891ea7b84f6b790be05b",
|
||||
"sha256:d1c2676e3d840852a2de7c7d5d76407c772927addff8d742b9808fe0afccebdf",
|
||||
"sha256:d7124f52f3bd259f510651450e18e0fd081ed82f3c08541dffc7b94b883aa981",
|
||||
"sha256:d900d949b707778696fdf01036f58c9876a0d8bfe116e8d220cfd4b15f14e741",
|
||||
"sha256:ebfd274dcd5133e0afae738e6d9da4323c3eb021b3e13052d8cbd0e457b1256e",
|
||||
"sha256:ed361bb83436f117f9917d282a456f9e5009ea12fd6de8742d1a4752c3017e93",
|
||||
"sha256:f5144c75445ae3ca2057faac03fda5a902eff196702b0a24daf1d6ce0650514b"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
|
||||
"version": "==1.6.0"
|
||||
},
|
||||
"mccabe": {
|
||||
"hashes": [
|
||||
"sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
|
||||
"sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
|
||||
],
|
||||
"version": "==0.6.1"
|
||||
},
|
||||
"mypy": {
|
||||
"hashes": [
|
||||
"sha256:0d0a87c0e7e3a9becdfbe936c981d32e5ee0ccda3e0f07e1ef2c3d1a817cf73e",
|
||||
"sha256:25adde9b862f8f9aac9d2d11971f226bd4c8fbaa89fb76bdadb267ef22d10064",
|
||||
"sha256:28fb5479c494b1bab244620685e2eb3c3f988d71fd5d64cc753195e8ed53df7c",
|
||||
"sha256:2f9b3407c58347a452fc0736861593e105139b905cca7d097e413453a1d650b4",
|
||||
"sha256:33f159443db0829d16f0a8d83d94df3109bb6dd801975fe86bacb9bf71628e97",
|
||||
"sha256:3f2aca7f68580dc2508289c729bd49ee929a436208d2b2b6aab15745a70a57df",
|
||||
"sha256:499c798053cdebcaa916eef8cd733e5584b5909f789de856b482cd7d069bdad8",
|
||||
"sha256:4eec37370483331d13514c3f55f446fc5248d6373e7029a29ecb7b7494851e7a",
|
||||
"sha256:552a815579aa1e995f39fd05dde6cd378e191b063f031f2acfe73ce9fb7f9e56",
|
||||
"sha256:5873888fff1c7cf5b71efbe80e0e73153fe9212fafdf8e44adfe4c20ec9f82d7",
|
||||
"sha256:61a3d5b97955422964be6b3baf05ff2ce7f26f52c85dd88db11d5e03e146a3a6",
|
||||
"sha256:674e822aa665b9fd75130c6c5f5ed9564a38c6cea6a6432ce47eafb68ee578c5",
|
||||
"sha256:7ce3175801d0ae5fdfa79b4f0cfed08807af4d075b402b7e294e6aa72af9aa2a",
|
||||
"sha256:9743c91088d396c1a5a3c9978354b61b0382b4e3c440ce83cf77994a43e8c521",
|
||||
"sha256:9f94aac67a2045ec719ffe6111df543bac7874cee01f41928f6969756e030564",
|
||||
"sha256:a26f8ec704e5a7423c8824d425086705e381b4f1dfdef6e3a1edab7ba174ec49",
|
||||
"sha256:abf7e0c3cf117c44d9285cc6128856106183938c68fd4944763003decdcfeb66",
|
||||
"sha256:b09669bcda124e83708f34a94606e01b614fa71931d356c1f1a5297ba11f110a",
|
||||
"sha256:cd07039aa5df222037005b08fbbfd69b3ab0b0bd7a07d7906de75ae52c4e3119",
|
||||
"sha256:d23e0ea196702d918b60c8288561e722bf437d82cb7ef2edcd98cfa38905d506",
|
||||
"sha256:d65cc1df038ef55a99e617431f0553cd77763869eebdf9042403e16089fe746c",
|
||||
"sha256:d7da2e1d5f558c37d6e8c1246f1aec1e7349e4913d8fb3cb289a35de573fe2eb"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.812"
|
||||
},
|
||||
"mypy-extensions": {
|
||||
"hashes": [
|
||||
"sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d",
|
||||
"sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"
|
||||
],
|
||||
"version": "==0.4.3"
|
||||
},
|
||||
"pathspec": {
|
||||
"hashes": [
|
||||
"sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd",
|
||||
"sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"
|
||||
],
|
||||
"version": "==0.8.1"
|
||||
},
|
||||
"pycodestyle": {
|
||||
"hashes": [
|
||||
"sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068",
|
||||
"sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.7.0"
|
||||
},
|
||||
"pyflakes": {
|
||||
"hashes": [
|
||||
"sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3",
|
||||
"sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.3.1"
|
||||
},
|
||||
"pylint": {
|
||||
"hashes": [
|
||||
"sha256:209d712ec870a0182df034ae19f347e725c1e615b2269519ab58a35b3fcbbe7a",
|
||||
"sha256:bd38914c7731cdc518634a8d3c5585951302b6e2b6de60fbb3f7a0220e21eeee"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.7.4"
|
||||
},
|
||||
"pylint-django": {
|
||||
"hashes": [
|
||||
"sha256:a5a4515209a6237d1d390a4a307d53f53baaf4f058ecf4bb556c775d208f6b0d",
|
||||
"sha256:dc5ed27bb7662d73444ccd15a0b3964ed6ced6cc2712b85db616102062d2ec35"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.4.3"
|
||||
},
|
||||
"pylint-plugin-utils": {
|
||||
"hashes": [
|
||||
"sha256:2f30510e1c46edf268d3a195b2849bd98a1b9433229bb2ba63b8d776e1fc4d0a",
|
||||
"sha256:57625dcca20140f43731311cd8fd879318bf45a8b0fd17020717a8781714a25a"
|
||||
],
|
||||
"version": "==0.6"
|
||||
},
|
||||
"pytz": {
|
||||
"hashes": [
|
||||
"sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da",
|
||||
"sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"
|
||||
],
|
||||
"version": "==2021.1"
|
||||
},
|
||||
"regex": {
|
||||
"hashes": [
|
||||
"sha256:01afaf2ec48e196ba91b37451aa353cb7eda77efe518e481707e0515025f0cd5",
|
||||
"sha256:11d773d75fa650cd36f68d7ca936e3c7afaae41b863b8c387a22aaa78d3c5c79",
|
||||
"sha256:18c071c3eb09c30a264879f0d310d37fe5d3a3111662438889ae2eb6fc570c31",
|
||||
"sha256:1e1c20e29358165242928c2de1482fb2cf4ea54a6a6dea2bd7a0e0d8ee321500",
|
||||
"sha256:281d2fd05555079448537fe108d79eb031b403dac622621c78944c235f3fcf11",
|
||||
"sha256:314d66636c494ed9c148a42731b3834496cc9a2c4251b1661e40936814542b14",
|
||||
"sha256:32e65442138b7b76dd8173ffa2cf67356b7bc1768851dded39a7a13bf9223da3",
|
||||
"sha256:339456e7d8c06dd36a22e451d58ef72cef293112b559010db3d054d5560ef439",
|
||||
"sha256:3916d08be28a1149fb97f7728fca1f7c15d309a9f9682d89d79db75d5e52091c",
|
||||
"sha256:3a9cd17e6e5c7eb328517969e0cb0c3d31fd329298dd0c04af99ebf42e904f82",
|
||||
"sha256:47bf5bf60cf04d72bf6055ae5927a0bd9016096bf3d742fa50d9bf9f45aa0711",
|
||||
"sha256:4c46e22a0933dd783467cf32b3516299fb98cfebd895817d685130cc50cd1093",
|
||||
"sha256:4c557a7b470908b1712fe27fb1ef20772b78079808c87d20a90d051660b1d69a",
|
||||
"sha256:52ba3d3f9b942c49d7e4bc105bb28551c44065f139a65062ab7912bef10c9afb",
|
||||
"sha256:563085e55b0d4fb8f746f6a335893bda5c2cef43b2f0258fe1020ab1dd874df8",
|
||||
"sha256:598585c9f0af8374c28edd609eb291b5726d7cbce16be6a8b95aa074d252ee17",
|
||||
"sha256:619d71c59a78b84d7f18891fe914446d07edd48dc8328c8e149cbe0929b4e000",
|
||||
"sha256:67bdb9702427ceddc6ef3dc382455e90f785af4c13d495f9626861763ee13f9d",
|
||||
"sha256:6d1b01031dedf2503631d0903cb563743f397ccaf6607a5e3b19a3d76fc10480",
|
||||
"sha256:741a9647fcf2e45f3a1cf0e24f5e17febf3efe8d4ba1281dcc3aa0459ef424dc",
|
||||
"sha256:7c2a1af393fcc09e898beba5dd59196edaa3116191cc7257f9224beaed3e1aa0",
|
||||
"sha256:7d9884d86dd4dd489e981d94a65cd30d6f07203d90e98f6f657f05170f6324c9",
|
||||
"sha256:90f11ff637fe8798933fb29f5ae1148c978cccb0452005bf4c69e13db951e765",
|
||||
"sha256:919859aa909429fb5aa9cf8807f6045592c85ef56fdd30a9a3747e513db2536e",
|
||||
"sha256:96fcd1888ab4d03adfc9303a7b3c0bd78c5412b2bfbe76db5b56d9eae004907a",
|
||||
"sha256:97f29f57d5b84e73fbaf99ab3e26134e6687348e95ef6b48cfd2c06807005a07",
|
||||
"sha256:980d7be47c84979d9136328d882f67ec5e50008681d94ecc8afa8a65ed1f4a6f",
|
||||
"sha256:a91aa8619b23b79bcbeb37abe286f2f408d2f2d6f29a17237afda55bb54e7aac",
|
||||
"sha256:ade17eb5d643b7fead300a1641e9f45401c98eee23763e9ed66a43f92f20b4a7",
|
||||
"sha256:b9c3db21af35e3b3c05764461b262d6f05bbca08a71a7849fd79d47ba7bc33ed",
|
||||
"sha256:bd28bc2e3a772acbb07787c6308e00d9626ff89e3bfcdebe87fa5afbfdedf968",
|
||||
"sha256:bf5824bfac591ddb2c1f0a5f4ab72da28994548c708d2191e3b87dd207eb3ad7",
|
||||
"sha256:c0502c0fadef0d23b128605d69b58edb2c681c25d44574fc673b0e52dce71ee2",
|
||||
"sha256:c38c71df845e2aabb7fb0b920d11a1b5ac8526005e533a8920aea97efb8ec6a4",
|
||||
"sha256:ce15b6d103daff8e9fee13cf7f0add05245a05d866e73926c358e871221eae87",
|
||||
"sha256:d3029c340cfbb3ac0a71798100ccc13b97dddf373a4ae56b6a72cf70dfd53bc8",
|
||||
"sha256:e512d8ef5ad7b898cdb2d8ee1cb09a8339e4f8be706d27eaa180c2f177248a10",
|
||||
"sha256:e8e5b509d5c2ff12f8418006d5a90e9436766133b564db0abaec92fd27fcee29",
|
||||
"sha256:ee54ff27bf0afaf4c3b3a62bcd016c12c3fdb4ec4f413391a90bd38bc3624605",
|
||||
"sha256:fa4537fb4a98fe8fde99626e4681cc644bdcf2a795038533f9f711513a862ae6",
|
||||
"sha256:fd45ff9293d9274c5008a2054ecef86a9bfe819a67c7be1afb65e69b405b3042"
|
||||
],
|
||||
"version": "==2021.4.4"
|
||||
},
|
||||
"sqlparse": {
|
||||
"hashes": [
|
||||
"sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0",
|
||||
"sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==0.4.1"
|
||||
},
|
||||
"toml": {
|
||||
"hashes": [
|
||||
"sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
|
||||
"sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==0.10.2"
|
||||
},
|
||||
"typed-ast": {
|
||||
"hashes": [
|
||||
"sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace",
|
||||
"sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff",
|
||||
"sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266",
|
||||
"sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528",
|
||||
"sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6",
|
||||
"sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808",
|
||||
"sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4",
|
||||
"sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363",
|
||||
"sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341",
|
||||
"sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04",
|
||||
"sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41",
|
||||
"sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e",
|
||||
"sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3",
|
||||
"sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899",
|
||||
"sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805",
|
||||
"sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c",
|
||||
"sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c",
|
||||
"sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39",
|
||||
"sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a",
|
||||
"sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3",
|
||||
"sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7",
|
||||
"sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f",
|
||||
"sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075",
|
||||
"sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0",
|
||||
"sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40",
|
||||
"sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428",
|
||||
"sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927",
|
||||
"sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3",
|
||||
"sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f",
|
||||
"sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.4.3"
|
||||
},
|
||||
"typing-extensions": {
|
||||
"hashes": [
|
||||
"sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918",
|
||||
"sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c",
|
||||
"sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"
|
||||
],
|
||||
"version": "==3.7.4.3"
|
||||
},
|
||||
"wrapt": {
|
||||
"hashes": [
|
||||
"sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"
|
||||
],
|
||||
"version": "==1.12.1"
|
||||
}
|
||||
}
|
||||
}
|
23
README.md
Normal file
23
README.md
Normal file
|
@ -0,0 +1,23 @@
|
|||
tjdests
|
||||
===
|
||||
|
||||
TJ Destinations, ala Ethan.
|
||||
|
||||
THIS WEBSITE IS NOT, IN ANY WAY, AFFILIATED WITH NOR ENDORSED BY THE
|
||||
THOMAS JEFFERSON HIGH SCHOOL FOR SCIENCE AND TECHNOLOGY (TJHSST),
|
||||
THE TJHSST COMPUTER SYSTEMS LAB, FAIRFAX COUNTY PUBLIC SCHOOLS,
|
||||
OR ANY SUBSIDIARY, AFFILIATE, DEPARTMENT, OR PARTNER THEREOF.
|
||||
|
||||
---
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of version 3 of the GNU Affero General Public
|
||||
License as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
22
manage.py
Executable file
22
manage.py
Executable file
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/env python
|
||||
"""Django's command-line utility for administrative tasks."""
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
"""Run administrative tasks."""
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tjdests.settings')
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
except ImportError as exc:
|
||||
raise ImportError(
|
||||
"Couldn't import Django. Are you sure it's installed and "
|
||||
"available on your PYTHONPATH environment variable? Did you "
|
||||
"forget to activate a virtual environment?"
|
||||
) from exc
|
||||
execute_from_command_line(sys.argv)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
0
tjdests/__init__.py
Normal file
0
tjdests/__init__.py
Normal file
0
tjdests/apps/__init__.py
Normal file
0
tjdests/apps/__init__.py
Normal file
0
tjdests/apps/authentication/__init__.py
Normal file
0
tjdests/apps/authentication/__init__.py
Normal file
5
tjdests/apps/authentication/admin.py
Normal file
5
tjdests/apps/authentication/admin.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from .models import User
|
||||
|
||||
admin.site.register(User)
|
15
tjdests/apps/authentication/decorators.py
Normal file
15
tjdests/apps/authentication/decorators.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
import functools
|
||||
|
||||
from django.http import HttpRequest
|
||||
from django.shortcuts import redirect
|
||||
|
||||
|
||||
def require_accept_tos(func):
|
||||
@functools.wraps(func)
|
||||
def wrapper(request: HttpRequest, *args, **kwargs):
|
||||
if request.user.is_authenticated and not request.user.accepted_terms:
|
||||
return redirect("authentication:tos")
|
||||
|
||||
return func(request, *args, **kwargs)
|
||||
|
||||
return wrapper
|
47
tjdests/apps/authentication/forms.py
Normal file
47
tjdests/apps/authentication/forms.py
Normal file
|
@ -0,0 +1,47 @@
|
|||
from django import forms
|
||||
from django.contrib.auth import password_validation
|
||||
|
||||
from crispy_forms.helper import FormHelper
|
||||
from crispy_forms.layout import Submit
|
||||
|
||||
|
||||
class TOSForm(forms.Form):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.helper = FormHelper()
|
||||
self.helper.form_method = 'post'
|
||||
|
||||
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.")
|
||||
|
||||
password = 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.")
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super(TOSForm, self).clean()
|
||||
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.",]})
|
||||
|
||||
# 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.",]})
|
||||
|
||||
if not understand_no_reset:
|
||||
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)
|
||||
|
||||
|
46
tjdests/apps/authentication/migrations/0001_initial.py
Normal file
46
tjdests/apps/authentication/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,46 @@
|
|||
# Generated by Django 3.2 on 2021-04-19 15:03
|
||||
|
||||
import django.contrib.auth.models
|
||||
import django.contrib.auth.validators
|
||||
from django.db import migrations, models
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
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)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'user',
|
||||
'verbose_name_plural': 'users',
|
||||
'abstract': False,
|
||||
},
|
||||
managers=[
|
||||
('objects', django.contrib.auth.models.UserManager()),
|
||||
],
|
||||
),
|
||||
]
|
33
tjdests/apps/authentication/migrations/0002_initial.py
Normal file
33
tjdests/apps/authentication/migrations/0002_initial.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
# Generated by Django 3.2 on 2021-04-19 15:03
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('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'),
|
||||
),
|
||||
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'),
|
||||
),
|
||||
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'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2 on 2021-04-19 16:00
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('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'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,25 @@
|
|||
# Generated by Django 3.2 on 2021-04-19 17:13
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('destinations', '0005_alter_decision_admission_status'),
|
||||
('authentication', '0003_alter_user_publish_data'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
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'),
|
||||
),
|
||||
]
|
0
tjdests/apps/authentication/migrations/__init__.py
Normal file
0
tjdests/apps/authentication/migrations/__init__.py
Normal file
22
tjdests/apps/authentication/models.py
Normal file
22
tjdests/apps/authentication/models.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
from django.db import models
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
|
||||
from ..destinations.models import Decision, TestScore
|
||||
|
||||
class User(AbstractUser):
|
||||
accepted_terms = models.BooleanField(default=False)
|
||||
graduation_year = models.PositiveSmallIntegerField(null=True)
|
||||
|
||||
is_senior = models.BooleanField(default=False)
|
||||
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.")
|
||||
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.")
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.first_name} {self.last_name}"
|
38
tjdests/apps/authentication/oauth.py
Normal file
38
tjdests/apps/authentication/oauth.py
Normal file
|
@ -0,0 +1,38 @@
|
|||
from django.conf import settings
|
||||
from social_core.backends.oauth import BaseOAuth2
|
||||
|
||||
|
||||
class IonOauth2(BaseOAuth2):
|
||||
name = "ion"
|
||||
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")]
|
||||
|
||||
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"]}
|
||||
)
|
||||
# fields used to populate/update User model
|
||||
|
||||
if not profile["graduation_year"]:
|
||||
profile["graduation_year"] = 0
|
||||
|
||||
return {
|
||||
"id": profile["id"],
|
||||
"username": profile["ion_username"],
|
||||
"first_name": profile["first_name"],
|
||||
"last_name": profile["last_name"],
|
||||
"full_name": profile["full_name"],
|
||||
"email": profile["tj_email"],
|
||||
"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
|
||||
}
|
||||
|
||||
def get_user_id(self, details, response):
|
||||
return details["id"]
|
12
tjdests/apps/authentication/urls.py
Normal file
12
tjdests/apps/authentication/urls.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
from django.contrib.auth.views import LogoutView
|
||||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
app_name = "authentication"
|
||||
|
||||
urlpatterns = [
|
||||
path("", views.index_view, name="index"),
|
||||
path("login", views.LoginViewCustom.as_view(), name="login"),
|
||||
path("logout", LogoutView.as_view(), name="logout"),
|
||||
path("tos", views.accept_tos_view, name="tos"),
|
||||
]
|
50
tjdests/apps/authentication/views.py
Normal file
50
tjdests/apps/authentication/views.py
Normal file
|
@ -0,0 +1,50 @@
|
|||
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.urls import reverse
|
||||
|
||||
from tjdests.apps.authentication.decorators import require_accept_tos
|
||||
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
|
||||
|
||||
if not request.user.is_student:
|
||||
logout(request)
|
||||
messages.error(request, "You must be a student to access this site.")
|
||||
return redirect(reverse("authentication:index"))
|
||||
|
||||
if request.user.accepted_terms:
|
||||
return redirect(reverse("authentication:index"))
|
||||
|
||||
if request.method == "POST":
|
||||
form = TOSForm(request.POST)
|
||||
|
||||
if form.is_valid():
|
||||
request.user.accepted_terms = form.cleaned_data.get("accept_tos")
|
||||
request.user.set_password(form.cleaned_data.get("password"))
|
||||
request.user.save()
|
||||
|
||||
login(request, request.user, backend='django.contrib.auth.backends.ModelBackend')
|
||||
|
||||
messages.success(request, "You have logged in.")
|
||||
|
||||
return redirect(reverse("authentication:index"))
|
||||
else:
|
||||
form = TOSForm()
|
||||
|
||||
context = {"form": form}
|
||||
|
||||
return render(request, "authentication/accept_tos.html", context=context)
|
||||
|
||||
class LoginViewCustom(LoginView):
|
||||
template_name = "authentication/login.html"
|
||||
|
4
tjdests/apps/context_processors.py
Normal file
4
tjdests/apps/context_processors.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
from django.conf import settings
|
||||
|
||||
def settings_renderer(request):
|
||||
return {"settings": settings}
|
0
tjdests/apps/destinations/__init__.py
Normal file
0
tjdests/apps/destinations/__init__.py
Normal file
7
tjdests/apps/destinations/admin.py
Normal file
7
tjdests/apps/destinations/admin.py
Normal file
|
@ -0,0 +1,7 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from .models import College, TestScore, Decision
|
||||
|
||||
admin.site.register(College)
|
||||
admin.site.register(TestScore)
|
||||
admin.site.register(Decision)
|
0
tjdests/apps/destinations/management/__init__.py
Normal file
0
tjdests/apps/destinations/management/__init__.py
Normal file
28
tjdests/apps/destinations/management/commands/import_ceeb.py
Normal file
28
tjdests/apps/destinations/management/commands/import_ceeb.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
import argparse
|
||||
import csv
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
from ...models import College
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Imports a CSV of CEEB codes as colleges"
|
||||
|
||||
def add_arguments(self, parser: argparse.ArgumentParser):
|
||||
parser.add_argument("file_name", type=str)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
"""CSV format:
|
||||
|
||||
CEEB, College Name, City, State
|
||||
"""
|
||||
with open(options["file_name"], "r") as file:
|
||||
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']}"})
|
||||
|
||||
if result[1]:
|
||||
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)
|
44
tjdests/apps/destinations/migrations/0001_initial.py
Normal file
44
tjdests/apps/destinations/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,44 @@
|
|||
# Generated by Django 3.2 on 2021-04-19 15:03
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
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)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
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)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
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)),
|
||||
],
|
||||
),
|
||||
]
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2 on 2021-04-19 15:38
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('destinations', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='decision',
|
||||
name='admitted',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2 on 2021-04-19 15:47
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('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),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2 on 2021-04-19 16:00
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('destinations', '0003_alter_decision_admitted'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='decision',
|
||||
old_name='admitted',
|
||||
new_name='admission_status',
|
||||
),
|
||||
]
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2 on 2021-04-19 17:13
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('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),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2 on 2021-04-19 18:40
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('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'),
|
||||
),
|
||||
]
|
0
tjdests/apps/destinations/migrations/__init__.py
Normal file
0
tjdests/apps/destinations/migrations/__init__.py
Normal file
217
tjdests/apps/destinations/models.py
Normal file
217
tjdests/apps/destinations/models.py
Normal file
|
@ -0,0 +1,217 @@
|
|||
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")
|
||||
name = models.CharField(max_length=250, null=False, blank=False)
|
||||
location = models.CharField(max_length=250, null=False, blank=False)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name} - {self.location} ({self.ceeb_code})"
|
||||
|
||||
|
||||
class Decision(models.Model):
|
||||
"""Represents a college decision."""
|
||||
|
||||
EARLY_DECISION = "ED"
|
||||
EARLY_DECISION_2 = "ED2"
|
||||
EARLY_ACTION = "EA"
|
||||
EARLY_ACTION_2 = "EA2"
|
||||
REGULAR_DECISION = "RD"
|
||||
ROLLING = "RL"
|
||||
|
||||
DECISION_TYPE_CHOICES = [
|
||||
(EARLY_DECISION, "Early Decision"),
|
||||
(EARLY_DECISION_2, "Early Decision 2"),
|
||||
(EARLY_ACTION, "Early Action"),
|
||||
(EARLY_ACTION_2, "Early Action 2"),
|
||||
(REGULAR_DECISION, "Regular Decision"),
|
||||
(ROLLING, "Rolling"),
|
||||
]
|
||||
|
||||
user = models.ForeignKey("authentication.User", on_delete=models.CASCADE)
|
||||
|
||||
decision_type = models.CharField(max_length=20, choices=DECISION_TYPE_CHOICES, null=True)
|
||||
|
||||
ADMIT = "ADMIT"
|
||||
WAITLIST_ADMIT = "WAITLIST_ADMIT"
|
||||
WAITLIST_DENY = "WAITLIST_DENY"
|
||||
WAITLIST = "WAITLIST"
|
||||
DEFER_ADMIT = "DEFER_ADMIT"
|
||||
DEFER_DENY = "DEFER_DENY"
|
||||
DEFER = "DEFER"
|
||||
DENY = "DENY"
|
||||
|
||||
ADMIT_TYPE_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"),
|
||||
]
|
||||
|
||||
admission_status = models.CharField(max_length=20, choices=ADMIT_TYPE_CHOICES)
|
||||
college = models.ForeignKey(College, on_delete=models.CASCADE)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.college.name} - {self.get_decision_type_display()}: {self.get_admission_status_display()}"
|
||||
|
||||
|
||||
class TestScore(models.Model):
|
||||
"""Represents a test score."""
|
||||
|
||||
# Test score types for validation purposes
|
||||
ACT_ENGL = "ACT_ENGL"
|
||||
ACT_MATH = "ACT_MATH"
|
||||
ACT_READ = "ACT_READ"
|
||||
ACT_SCI = "ACT_SCI"
|
||||
ACT_COMP = "ACT_COMP"
|
||||
|
||||
# SAT
|
||||
SAT_EBRW = "SAT_EBRW"
|
||||
SAT_MATH = "SAT_MATH"
|
||||
SAT_TOTAL = "SAT_TOTAL"
|
||||
|
||||
# SAT Subject Tests
|
||||
SAT2_MATH1 = "SAT2_MATH1"
|
||||
SAT2_MATH2 = "SAT2_MATH2"
|
||||
SAT2_BIO = "SAT2_BIO"
|
||||
SAT2_CHEM = "SAT2_CHEM"
|
||||
SAT2_PHYS = "SAT2_PHYS"
|
||||
SAT2_ENGL = "SAT2_ENGL"
|
||||
SAT2_USH = "SAT2_USH"
|
||||
SAT2_WH = "SAT2_WH"
|
||||
SAT2_ES = "SAT2_ES"
|
||||
SAT2_ESL = "SAT2_ESL"
|
||||
SAT2_FR = "SAT2_FR"
|
||||
SAT2_FRL = "SAT2_FRL"
|
||||
SAT2_ZHL = "SAT2_ZHL"
|
||||
SAT2_IT = "SAT2_IT"
|
||||
SAT2_DE = "SAT2_DE"
|
||||
SAT2_DEL = "SAT2_DEL"
|
||||
SAT2_HE = "SAT2_HE"
|
||||
SAT2_LA = "SAT2_LA"
|
||||
SAT2_JAL = "SAT2_JAL"
|
||||
SAT2_KOL = "SAT2_KOL"
|
||||
|
||||
# AP Exams
|
||||
AP_RSRCH = "AP_RSRCH"
|
||||
AP_SMNR = "AP_SMNR"
|
||||
AP_ART2D = "AP_ART2D"
|
||||
AP_ART3D = "AP_ART3D"
|
||||
AP_ARTDRAW = "AP_ARTDRAW"
|
||||
AP_ARTHIST = "AP_ARTHIST"
|
||||
AP_BIO = "AP_BIO"
|
||||
AP_CALCAB = "AP_CALCAB"
|
||||
AP_CALCBC = "AP_CALCBC"
|
||||
AP_CHEM = "AP_CHEM"
|
||||
AP_ZHLANG = "AP_ZHLANG"
|
||||
AP_CSA = "AP_CSA"
|
||||
AP_CSP = "AP_CSP"
|
||||
AP_ENLANG = "AP_ENLANG"
|
||||
AP_ENLIT = "AP_ENLIT"
|
||||
AP_ENVSCI = "AP_ENVSCI"
|
||||
AP_EUROHIST = "AP_EUROHIST"
|
||||
AP_FRLANG = "AP_FRLANG"
|
||||
AP_DELANG = "AP_DELANG"
|
||||
AP_GOVCOMP = "AP_GOVCOMP"
|
||||
AP_GOVUS = "AP_GOVUS"
|
||||
AP_HUG = "AP_HUG"
|
||||
AP_ITLANG = "AP_ITLANG"
|
||||
AP_JALANG = "AP_JALANG"
|
||||
AP_LATIN = "AP_LATIN"
|
||||
AP_MACRO = "AP_MACRO"
|
||||
AP_MICRO = "AP_MICRO"
|
||||
AP_MUSTHRY = "AP_MUSTHRY"
|
||||
AP_PHYSICS1 = "AP_PHYSICS1"
|
||||
AP_PHYSICS2 = "AP_PHYSICS2"
|
||||
AP_PHYSICSCEM = "AP_PHYSICSCEM"
|
||||
AP_PHYSICSCM = "AP_PHYSICSCM"
|
||||
AP_PSYCH = "AP_PSYCH"
|
||||
AP_ESLANG = "AP_ESLANG"
|
||||
AP_ESLIT = "AP_ESLIT"
|
||||
AP_STAT = "AP_STAT"
|
||||
AP_USH = "AP_USH"
|
||||
AP_WHM = "AP_WHM"
|
||||
|
||||
TEST_TYPES = [
|
||||
(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"),
|
||||
]
|
||||
|
||||
user = models.ForeignKey("authentication.User", on_delete=models.CASCADE)
|
||||
|
||||
exam_type = models.CharField(max_length=20, choices=TEST_TYPES, null=False)
|
||||
exam_score = models.PositiveSmallIntegerField(null=False)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.get_exam_type_display()}: {self.exam_score}"
|
9
tjdests/apps/destinations/urls.py
Normal file
9
tjdests/apps/destinations/urls.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
app_name = "destinations"
|
||||
|
||||
urlpatterns = [
|
||||
path("", views.StudentDestinationListView.as_view(), name="students"),
|
||||
path("colleges", views.CollegeDestinationListView.as_view(), name="colleges"),
|
||||
]
|
71
tjdests/apps/destinations/views.py
Normal file
71
tjdests/apps/destinations/views.py
Normal file
|
@ -0,0 +1,71 @@
|
|||
from django.contrib.auth.mixins import UserPassesTestMixin, LoginRequiredMixin
|
||||
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
|
||||
|
||||
|
||||
class StudentDestinationListView(LoginRequiredMixin, UserPassesTestMixin, ListView):
|
||||
model = User
|
||||
paginate_by = 20
|
||||
|
||||
def get_queryset(self):
|
||||
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:
|
||||
get_object_or_404(College, id=college_id)
|
||||
queryset = queryset.filter(decision__college__id=college_id)
|
||||
|
||||
return queryset
|
||||
|
||||
def get_context_data(self, *, object_list=None, **kwargs):
|
||||
context = super(StudentDestinationListView, self).get_context_data(**kwargs)
|
||||
|
||||
college_id = self.request.GET.get("college", None)
|
||||
if college_id is not None:
|
||||
context["college"] = get_object_or_404(College, id=college_id)
|
||||
|
||||
return context
|
||||
|
||||
def test_func(self):
|
||||
return self.request.user.accepted_terms
|
||||
|
||||
template_name = "destinations/student_list.html"
|
||||
|
||||
|
||||
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")
|
||||
|
||||
def test_func(self):
|
||||
return self.request.user.accepted_terms
|
||||
|
||||
template_name = "destinations/college_list.html"
|
0
tjdests/apps/profile/__init__.py
Normal file
0
tjdests/apps/profile/__init__.py
Normal file
28
tjdests/apps/profile/forms.py
Normal file
28
tjdests/apps/profile/forms.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
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
|
||||
|
||||
|
||||
class ProfilePublishForm(forms.ModelForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.helper = FormHelper()
|
||||
self.helper.form_method = 'post'
|
||||
|
||||
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])
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ["publish_data", "biography", "attending_decision"]
|
||||
|
||||
class DecisionForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Decision
|
||||
fields = ["college", "decision_type", "admission_status"]
|
14
tjdests/apps/profile/urls.py
Normal file
14
tjdests/apps/profile/urls.py
Normal file
|
@ -0,0 +1,14 @@
|
|||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
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("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"),
|
||||
]
|
141
tjdests/apps/profile/views.py
Normal file
141
tjdests/apps/profile/views.py
Normal file
|
@ -0,0 +1,141 @@
|
|||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.mixins import UserPassesTestMixin, LoginRequiredMixin
|
||||
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 tjdests.apps.authentication.decorators import require_accept_tos
|
||||
from tjdests.apps.destinations.models import TestScore, Decision
|
||||
|
||||
from .forms import ProfilePublishForm, DecisionForm
|
||||
|
||||
|
||||
@login_required
|
||||
@require_accept_tos
|
||||
def profile_view(request: HttpRequest):
|
||||
test_scores = TestScore.objects.filter(user=request.user)
|
||||
decisions = Decision.objects.filter(user=request.user)
|
||||
|
||||
# A POST request would mean that the user is saving their profile publication status
|
||||
if request.method == "POST":
|
||||
profile_form = ProfilePublishForm(request.POST, instance=request.user)
|
||||
if profile_form.is_valid():
|
||||
profile_form.save()
|
||||
|
||||
messages.success(request, "Your preferences have been changed.")
|
||||
else:
|
||||
profile_form = ProfilePublishForm(instance=request.user)
|
||||
|
||||
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):
|
||||
model = TestScore
|
||||
fields = ["exam_type", "exam_score"]
|
||||
template_name = "profile/testscore_form.html"
|
||||
success_message = "Test score created successfully."
|
||||
|
||||
def form_valid(self, form):
|
||||
form.instance.user = self.request.user
|
||||
return super().form_valid(form)
|
||||
|
||||
def test_func(self):
|
||||
return self.request.user.is_senior and self.request.user.accepted_terms
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse("profile:index")
|
||||
|
||||
|
||||
class TestScoreUpdateView(LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, UpdateView):
|
||||
model = TestScore
|
||||
fields = ["exam_type", "exam_score"]
|
||||
template_name = "profile/testscore_form.html"
|
||||
success_message = "Test score updated successfully."
|
||||
|
||||
def form_valid(self, form):
|
||||
form.instance.user = self.request.user
|
||||
return super().form_valid(form)
|
||||
|
||||
def get_queryset(self):
|
||||
owner = self.request.user
|
||||
return self.model.objects.filter(user=owner)
|
||||
|
||||
def test_func(self):
|
||||
return self.request.user.is_senior and self.request.user.accepted_terms
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse("profile:index")
|
||||
|
||||
|
||||
class TestScoreDeleteView(LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, DeleteView):
|
||||
model = TestScore
|
||||
template_name = "profile/testscore_delete.html"
|
||||
success_message = "Test score deleted successfully."
|
||||
|
||||
def get_queryset(self):
|
||||
owner = self.request.user
|
||||
return self.model.objects.filter(user=owner)
|
||||
|
||||
def test_func(self):
|
||||
return self.request.user.is_senior and self.request.user.accepted_terms
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse("profile:index")
|
||||
|
||||
class DecisionCreateView(LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, CreateView):
|
||||
model = Decision
|
||||
fields = ["college", "decision_type", "admission_status"]
|
||||
template_name = "profile/decision_form.html"
|
||||
success_message = "Decision created successfully."
|
||||
|
||||
def form_valid(self, form):
|
||||
form.instance.user = self.request.user
|
||||
return super().form_valid(form)
|
||||
|
||||
def test_func(self):
|
||||
return self.request.user.is_senior and self.request.user.accepted_terms
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse("profile:index")
|
||||
|
||||
|
||||
class DecisionUpdateView(LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, UpdateView):
|
||||
model = Decision
|
||||
fields = ["college", "decision_type", "admission_status"]
|
||||
template_name = "profile/decision_form.html"
|
||||
success_message = "Decision created successfully."
|
||||
|
||||
def form_valid(self, form):
|
||||
form.instance.user = self.request.user
|
||||
return super().form_valid(form)
|
||||
|
||||
def get_queryset(self):
|
||||
owner = self.request.user
|
||||
return self.model.objects.filter(user=owner)
|
||||
|
||||
def test_func(self):
|
||||
return self.request.user.is_senior and self.request.user.accepted_terms
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse("profile:index")
|
||||
|
||||
|
||||
class DecisionDeleteView(LoginRequiredMixin, SuccessMessageMixin, UserPassesTestMixin, DeleteView):
|
||||
model = Decision
|
||||
template_name = "profile/decision_delete.html"
|
||||
success_message = "Decision deleted successfully."
|
||||
|
||||
def get_queryset(self):
|
||||
owner = self.request.user
|
||||
return self.model.objects.filter(user=owner)
|
||||
|
||||
def test_func(self):
|
||||
return self.request.user.is_senior and self.request.user.accepted_terms
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse("profile:index")
|
16
tjdests/asgi.py
Normal file
16
tjdests/asgi.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
"""
|
||||
ASGI config for tjdests project.
|
||||
|
||||
It exposes the ASGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.asgi import get_asgi_application
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tjdests.settings')
|
||||
|
||||
application = get_asgi_application()
|
160
tjdests/settings/__init__.py
Normal file
160
tjdests/settings/__init__.py
Normal file
|
@ -0,0 +1,160 @@
|
|||
"""
|
||||
Django settings for tjdests project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 3.2.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/3.2/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/3.2/ref/settings/
|
||||
"""
|
||||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# 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'
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = []
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'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.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',
|
||||
]
|
||||
|
||||
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',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
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',
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
},
|
||||
]
|
||||
|
||||
AUTH_USER_MODEL = "authentication.User"
|
||||
|
||||
AUTHENTICATION_BACKENDS = ("tjdests.apps.authentication.oauth.IonOauth2", "django.contrib.auth.backends.ModelBackend",)
|
||||
|
||||
SOCIAL_AUTH_REDIRECT_IS_HTTPS = False
|
||||
SOCIAL_AUTH_ION_KEY = ""
|
||||
SOCIAL_AUTH_ION_SECRET = ""
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/3.2/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/3.2/howto/static-files/
|
||||
|
||||
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'
|
||||
|
||||
LOGIN_REDIRECT_URL = "authentication:tos"
|
||||
LOGOUT_REDIRECT_URL = "authentication:index"
|
||||
|
||||
LOGIN_URL = "authentication:login"
|
||||
|
||||
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
|
||||
CRISPY_TEMPLATE_PACK = "bootstrap5"
|
||||
|
||||
try:
|
||||
from .secret import *
|
||||
except ImportError:
|
||||
logging.warning("Error importing secret.py")
|
||||
pass
|
17
tjdests/settings/secret.sample.py
Normal file
17
tjdests/settings/secret.sample.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Deployed senior graduation year
|
||||
# e.g. if deploying in spring 2021, then 2021
|
||||
SENIOR_GRAD_YEAR = 2021
|
||||
|
||||
# Branding name
|
||||
BRANDING_NAME = "TJ Destinations"
|
||||
|
||||
# DEBUG and authorized hosts
|
||||
DEBUG = True
|
||||
ALLOWED_HOSTS = []
|
||||
|
||||
# secret
|
||||
SECRET_KEY = 'supersecret'
|
||||
|
||||
# OAuth
|
||||
SOCIAL_AUTH_ION_KEY = "ionkey"
|
||||
SOCIAL_AUTH_ION_SECRET = "ionsecret"
|
7
tjdests/static/bootstrap.bundle.min.js
vendored
Normal file
7
tjdests/static/bootstrap.bundle.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7
tjdests/static/bootstrap.min.css
vendored
Normal file
7
tjdests/static/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
698
tjdests/templates/authentication/accept_tos.html
Normal file
698
tjdests/templates/authentication/accept_tos.html
Normal file
|
@ -0,0 +1,698 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Login</h2>
|
||||
<p>To continue to log in, you must accept the terms below and set a permanent password.</p>
|
||||
<p>Your username is <b>{{ request.user.username }}</b>.</p>
|
||||
|
||||
<div style="height: 200px; margin-left: 10px; margin-bottom: 10px; border: 1px solid black;">
|
||||
<div style="height: inherit; overflow: auto; padding: 5px;">
|
||||
<h3 style="text-align: center;">GNU AFFERO GENERAL PUBLIC LICENSE</h3>
|
||||
<p style="text-align: center;">Version 3, 19 November 2007</p>
|
||||
|
||||
<p>Copyright © 2007 Free Software Foundation,
|
||||
Inc. <<a href="https://fsf.org/">https://fsf.org/</a>>
|
||||
<br />
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.</p>
|
||||
|
||||
<h4 id="preamble">Preamble</h4>
|
||||
|
||||
<p>The GNU Affero General Public License is a free, copyleft license
|
||||
for software and other kinds of works, specifically designed to ensure
|
||||
cooperation with the community in the case of network server software.</p>
|
||||
|
||||
<p>The licenses for most software and other practical works are
|
||||
designed to take away your freedom to share and change the works. By
|
||||
contrast, our General Public Licenses are intended to guarantee your
|
||||
freedom to share and change all versions of a program--to make sure it
|
||||
remains free software for all its users.</p>
|
||||
|
||||
<p>When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.</p>
|
||||
|
||||
<p>Developers that use our General Public Licenses protect your rights
|
||||
with two steps: (1) assert copyright on the software, and (2) offer
|
||||
you this License which gives you legal permission to copy, distribute
|
||||
and/or modify the software.</p>
|
||||
|
||||
<p>A secondary benefit of defending all users' freedom is that
|
||||
improvements made in alternate versions of the program, if they
|
||||
receive widespread use, become available for other developers to
|
||||
incorporate. Many developers of free software are heartened and
|
||||
encouraged by the resulting cooperation. However, in the case of
|
||||
software used on network servers, this result may fail to come about.
|
||||
The GNU General Public License permits making a modified version and
|
||||
letting the public access it on a server without ever releasing its
|
||||
source code to the public.</p>
|
||||
|
||||
<p>The GNU Affero General Public License is designed specifically to
|
||||
ensure that, in such cases, the modified source code becomes available
|
||||
to the community. It requires the operator of a network server to
|
||||
provide the source code of the modified version running there to the
|
||||
users of that server. Therefore, public use of a modified version, on
|
||||
a publicly accessible server, gives the public access to the source
|
||||
code of the modified version.</p>
|
||||
|
||||
<p>An older license, called the Affero General Public License and
|
||||
published by Affero, was designed to accomplish similar goals. This is
|
||||
a different license, not a version of the Affero GPL, but Affero has
|
||||
released a new version of the Affero GPL which permits relicensing under
|
||||
this license.</p>
|
||||
|
||||
<p>The precise terms and conditions for copying, distribution and
|
||||
modification follow.</p>
|
||||
|
||||
<h4 id="terms">TERMS AND CONDITIONS</h4>
|
||||
|
||||
<h4 id="section0">0. Definitions.</h4>
|
||||
|
||||
<p>"This License" refers to version 3 of the GNU Affero General Public
|
||||
License.</p>
|
||||
|
||||
<p>"Copyright" also means copyright-like laws that apply to other kinds
|
||||
of works, such as semiconductor masks.</p>
|
||||
|
||||
<p>"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.</p>
|
||||
|
||||
<p>To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.</p>
|
||||
|
||||
<p>A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.</p>
|
||||
|
||||
<p>To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.</p>
|
||||
|
||||
<p>To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.</p>
|
||||
|
||||
<p>An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.</p>
|
||||
|
||||
<h4 id="section1">1. Source Code.</h4>
|
||||
|
||||
<p>The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.</p>
|
||||
|
||||
<p>A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.</p>
|
||||
|
||||
<p>The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.</p>
|
||||
|
||||
<p>The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.</p>
|
||||
|
||||
<p>The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.</p>
|
||||
|
||||
<p>The Corresponding Source for a work in source code form is that
|
||||
same work.</p>
|
||||
|
||||
<h4 id="section2">2. Basic Permissions.</h4>
|
||||
|
||||
<p>All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.</p>
|
||||
|
||||
<p>You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.</p>
|
||||
|
||||
<p>Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.</p>
|
||||
|
||||
<h4 id="section3">3. Protecting Users' Legal Rights From Anti-Circumvention Law.</h4>
|
||||
|
||||
<p>No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.</p>
|
||||
|
||||
<p>When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.</p>
|
||||
|
||||
<h4 id="section4">4. Conveying Verbatim Copies.</h4>
|
||||
|
||||
<p>You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.</p>
|
||||
|
||||
<p>You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.</p>
|
||||
|
||||
<h4 id="section5">5. Conveying Modified Source Versions.</h4>
|
||||
|
||||
<p>You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:</p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li>a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.</li>
|
||||
|
||||
<li>b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".</li>
|
||||
|
||||
<li>c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.</li>
|
||||
|
||||
<li>d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<p>A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.</p>
|
||||
|
||||
<h4 id="section6">6. Conveying Non-Source Forms.</h4>
|
||||
|
||||
<p>You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:</p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li>a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.</li>
|
||||
|
||||
<li>b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.</li>
|
||||
|
||||
<li>c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.</li>
|
||||
|
||||
<li>d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.</li>
|
||||
|
||||
<li>e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<p>A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.</p>
|
||||
|
||||
<p>A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.</p>
|
||||
|
||||
<p>"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.</p>
|
||||
|
||||
<p>If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).</p>
|
||||
|
||||
<p>The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.</p>
|
||||
|
||||
<p>Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.</p>
|
||||
|
||||
<h4 id="section7">7. Additional Terms.</h4>
|
||||
|
||||
<p>"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.</p>
|
||||
|
||||
<p>When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.</p>
|
||||
|
||||
<p>Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:</p>
|
||||
|
||||
<ul>
|
||||
|
||||
<li>a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or</li>
|
||||
|
||||
<li>b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or</li>
|
||||
|
||||
<li>c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or</li>
|
||||
|
||||
<li>d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or</li>
|
||||
|
||||
<li>e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or</li>
|
||||
|
||||
<li>f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<p>All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further restriction,
|
||||
you may remove that term. If a license document contains a further
|
||||
restriction but permits relicensing or conveying under this License, you
|
||||
may add to a covered work material governed by the terms of that license
|
||||
document, provided that the further restriction does not survive such
|
||||
relicensing or conveying.</p>
|
||||
|
||||
<p>If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.</p>
|
||||
|
||||
<p>Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.</p>
|
||||
|
||||
<h4 id="section8">8. Termination.</h4>
|
||||
|
||||
<p>You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).</p>
|
||||
|
||||
<p>However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.</p>
|
||||
|
||||
<p>Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.</p>
|
||||
|
||||
<p>Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.</p>
|
||||
|
||||
<h4 id="section9">9. Acceptance Not Required for Having Copies.</h4>
|
||||
|
||||
<p>You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.</p>
|
||||
|
||||
<h4 id="section10">10. Automatic Licensing of Downstream Recipients.</h4>
|
||||
|
||||
<p>Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.</p>
|
||||
|
||||
<p>An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.</p>
|
||||
|
||||
<p>You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.</p>
|
||||
|
||||
<h4 id="section11">11. Patents.</h4>
|
||||
|
||||
<p>A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".</p>
|
||||
|
||||
<p>A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.</p>
|
||||
|
||||
<p>Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.</p>
|
||||
|
||||
<p>In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.</p>
|
||||
|
||||
<p>If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.</p>
|
||||
|
||||
<p>If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.</p>
|
||||
|
||||
<p>A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.</p>
|
||||
|
||||
<p>Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.</p>
|
||||
|
||||
<h4 id="section12">12. No Surrender of Others' Freedom.</h4>
|
||||
|
||||
<p>If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.</p>
|
||||
|
||||
<h4 id="section13">13. Remote Network Interaction; Use with the GNU General Public License.</h4>
|
||||
|
||||
<p>Notwithstanding any other provision of this License, if you modify the
|
||||
Program, your modified version must prominently offer all users
|
||||
interacting with it remotely through a computer network (if your version
|
||||
supports such interaction) an opportunity to receive the Corresponding
|
||||
Source of your version by providing access to the Corresponding Source
|
||||
from a network server at no charge, through some standard or customary
|
||||
means of facilitating copying of software. This Corresponding Source
|
||||
shall include the Corresponding Source for any work covered by version 3
|
||||
of the GNU General Public License that is incorporated pursuant to the
|
||||
following paragraph.</p>
|
||||
|
||||
<p>Notwithstanding any other provision of this License, you have permission
|
||||
to link or combine any covered work with a work licensed under version 3
|
||||
of the GNU General Public License into a single combined work, and to
|
||||
convey the resulting work. The terms of this License will continue to
|
||||
apply to the part which is the covered work, but the work with which it is
|
||||
combined will remain governed by version 3 of the GNU General Public
|
||||
License.</p>
|
||||
|
||||
<h4 id="section14">14. Revised Versions of this License.</h4>
|
||||
|
||||
<p>The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU Affero General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may differ
|
||||
in detail to address new problems or concerns.</p>
|
||||
|
||||
<p>Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU Affero
|
||||
General Public License "or any later version" applies to it, you have
|
||||
the option of following the terms and conditions either of that
|
||||
numbered version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number
|
||||
of the GNU Affero General Public License, you may choose any version
|
||||
ever published by the Free Software Foundation.</p>
|
||||
|
||||
<p>If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU Affero General Public License can be used, that
|
||||
proxy's public statement of acceptance of a version permanently
|
||||
authorizes you to choose that version for the Program.</p>
|
||||
|
||||
<p>Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.</p>
|
||||
|
||||
<h4 id="section15">15. Disclaimer of Warranty.</h4>
|
||||
|
||||
<p>THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.</p>
|
||||
|
||||
<h4 id="section16">16. Limitation of Liability.</h4>
|
||||
|
||||
<p>IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.</p>
|
||||
|
||||
<h4 id="section17">17. Interpretation of Sections 15 and 16.</h4>
|
||||
|
||||
<p>If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.</p>
|
||||
|
||||
<p>END OF TERMS AND CONDITIONS</p>
|
||||
|
||||
<h4 id="howto">How to Apply These Terms to Your New Programs</h4>
|
||||
|
||||
<p>If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.</p>
|
||||
|
||||
<p>To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.</p>
|
||||
|
||||
<pre> <one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
</pre>
|
||||
|
||||
<p>Also add information on how to contact you by electronic and paper mail.</p>
|
||||
|
||||
<p>If your software can interact with users remotely through a computer
|
||||
network, you should also make sure that it provides a way for users to
|
||||
get its source. For example, if your program is a web application, its
|
||||
interface could display a "Source" link that leads users to an archive
|
||||
of the code. There are many ways you could offer source, and different
|
||||
solutions will be better for different programs; see section 13 for the
|
||||
specific requirements.</p>
|
||||
|
||||
<p>You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
<<a href="https://www.gnu.org/licenses/">https://www.gnu.org/licenses/</a>>.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<form method="post">
|
||||
{% crispy form %}
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
44
tjdests/templates/authentication/index.html
Normal file
44
tjdests/templates/authentication/index.html
Normal file
|
@ -0,0 +1,44 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Welcome to {{ settings.SENIOR_GRAD_YEAR }} {{ settings.BRANDING_NAME }}</h2>
|
||||
|
||||
<p>
|
||||
This is intended to be a resource for:
|
||||
<ul>
|
||||
<li>the class of {{ settings.SENIOR_GRAD_YEAR }} to share its progress in the admissions process with one another.</li>
|
||||
<li>the class of {{ settings.SENIOR_GRAD_YEAR }} to share its achievements and college destinations with others.</li>
|
||||
<li>other classes as they prepare to apply for college.</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
{% if request.user.is_authenticated %}
|
||||
{% if request.user.is_senior %}
|
||||
<p>You may add destination information by navigating to your profile.</p>
|
||||
{% endif %}
|
||||
<p>You may browse student destinations using the links above.</p>
|
||||
{% else %}
|
||||
<p>You must sign in to see student destinations.</p>
|
||||
{% endif %}
|
||||
|
||||
<h3 id="important">IMPORTANT</h3>
|
||||
<p>
|
||||
THIS WEBSITE IS NOT, IN ANY WAY, AFFILIATED WITH NOR ENDORSED BY THE
|
||||
THOMAS JEFFERSON HIGH SCHOOL FOR SCIENCE AND TECHNOLOGY (TJHSST), THE
|
||||
TJHSST COMPUTER SYSTEMS LAB, FAIRFAX COUNTY PUBLIC SCHOOLS,
|
||||
OR ANY SUBSIDIARY, AFFILIATE, DEPARTMENT, OR PARTNER THEREOF.
|
||||
</p>
|
||||
<p>
|
||||
Your use of this website is subject to the terms outlined in
|
||||
version 3 of the GNU Affero General Public license; notably the terms
|
||||
that provide this software WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE; and the terms that limit the liability of
|
||||
any copyright holder(s) of this work. See the
|
||||
<a href="https://www.gnu.org/licenses/agpl-3.0.html" target="_blank">GNU Affero General Public License</a> for more details.
|
||||
</p>
|
||||
<p>
|
||||
This website is <a href="https://github.com/etnguyen03/tjdests" target="_blank">open source</a>, and is © 2021 Ethan Nguyen.
|
||||
All rights reserved.
|
||||
</p>
|
||||
|
||||
{% endblock %}
|
37
tjdests/templates/authentication/login.html
Normal file
37
tjdests/templates/authentication/login.html
Normal file
|
@ -0,0 +1,37 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Login</h2>
|
||||
<p>By logging in, you agree to the terms listed <a href="{% url "authentication:index" %}#important">at the bottom of the home page</a>.</p>
|
||||
|
||||
<div class="alert alert-primary" role="alert">
|
||||
<b>Is this your first time here?</b> If so, you will need to log in using Ion to establish an account first.
|
||||
After you have set a permanent password, you may log in using it, if you wish, or if you can no longer
|
||||
access your Ion account.
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="row align-items-start">
|
||||
<div class="col">
|
||||
<h4>Log in with Ion</h4>
|
||||
<form action="{% url "social:begin" "ion" %}{% if request.GET.next %}?next={{ request.GET.next|urlencode }}{% endif %}" method="POST">
|
||||
{% csrf_token %}
|
||||
<input type="submit" class="btn btn-primary" value="Login with Ion">
|
||||
</form>
|
||||
</div>
|
||||
<div class="col">
|
||||
<h4>Log in with Username and Password</h4>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{ form|crispy }}
|
||||
<div class="pt-3">
|
||||
<input type="submit" value="Login" class="btn btn-primary">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
79
tjdests/templates/base.html
Normal file
79
tjdests/templates/base.html
Normal file
|
@ -0,0 +1,79 @@
|
|||
{% load static %}
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.1.1/css/all.min.css">
|
||||
|
||||
<link href="{% static "bootstrap.min.css" %}" rel="stylesheet" integrity="sha384-eOJMYsd53ii+scO/bJGFsiCZc+5NDVN2yr8+0RDqr0Ql0h+rP48ckxlpbzKgwra6" crossorigin="anonymous">
|
||||
<script src="{% static "bootstrap.bundle.min.js" %}" integrity="sha384-JEW9xMcG8R+pH31jmWH6WWP0WintQrMb4s7ZOdauHnUtxwoG2vI5DkLtS3qm9Ekf" crossorigin="anonymous"></script>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.13.3/js/standalone/selectize.js" integrity="sha512-pF+DNRwavWMukUv/LyzDyDMn8U2uvqYQdJN0Zvilr6DDo/56xPDZdDoyPDYZRSL4aOKO/FGKXTpzDyQJ8je8Qw==" crossorigin="anonymous"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.13.3/css/selectize.bootstrap4.min.css" integrity="sha512-MMojOrCQrqLg4Iarid2YMYyZ7pzjPeXKRvhW9nZqLo6kPBBTuvNET9DBVWptAo/Q20Fy11EIHM5ig4WlIrJfQw==" crossorigin="anonymous" />
|
||||
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
$("select").each(function(){
|
||||
$(this).selectize();
|
||||
});
|
||||
$(function () {
|
||||
$('[data-toggle="tooltip"]').tooltip()
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<title>{{ settings.SENIOR_GRAD_YEAR }} {{ settings.BRANDING_NAME }}</title>
|
||||
</head>
|
||||
<body>
|
||||
<a class="visually-hidden-focusable" href="#content">Skip to main content</a>
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="{% url "authentication:index" %}">{{ settings.SENIOR_GRAD_YEAR }} {{ settings.BRANDING_NAME }}</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url "destinations:students" %}">Students</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url "destinations:colleges" %}">Colleges</a>
|
||||
</li>
|
||||
{% if request.user.is_authenticated %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url "profile:index" %}">Profile</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url "authentication:logout" %}">Logout</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container pt-3">
|
||||
{% if messages %}
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
{% for message in messages %}
|
||||
<div class="alert alert-{{ message.tags }}" role="alert">
|
||||
<p>{{ message }}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div id="content">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
61
tjdests/templates/destinations/college_list.html
Normal file
61
tjdests/templates/destinations/college_list.html
Normal file
|
@ -0,0 +1,61 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% load bootstrap_pagination %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Student Destinations by College</h2>
|
||||
|
||||
<p><b>Note</b>: All data is self-reported. We do not make any claim as to the accuracy of this data.</p>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">University Name</th>
|
||||
<th scope="col">Total Applications</th>
|
||||
<th scope="col">Admitted</th>
|
||||
<th scope="col">Waitlisted</th>
|
||||
<th scope="col">Waitlist-Admitted</th>
|
||||
<th scope="col">Waitlist-Denied</th>
|
||||
<th scope="col">Deferred</th>
|
||||
<th scope="col">Deferred-Admitted</th>
|
||||
<th scope="col">Deferred-Denied</th>
|
||||
<th scope="col">Denied</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for college in object_list %}
|
||||
<tr>
|
||||
<th scope="row"><a href="{% url "destinations:students" %}?college={{ college.id }}">{{ college.name }}</a></th>
|
||||
<td>{{ college.count_decisions }}</td>
|
||||
<td>{{ college.count_admit }}</td>
|
||||
<td>{{ college.count_waitlist }}</td>
|
||||
<td>{{ college.count_waitlist_admit }}</td>
|
||||
<td>{{ college.count_waitlist_deny }}</td>
|
||||
<td>{{ college.count_defer }}</td>
|
||||
<td>{{ college.count_defer_admit }}</td>
|
||||
<td>{{ college.count_defer_deny }}</td>
|
||||
<td>{{ college.count_deny }}</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td>There is no data to display.</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="row py-3">
|
||||
<div class="col justify-content-center">
|
||||
{% bootstrap_paginate page_obj range=10 extra_pagination_classes="justify-content-center" %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
121
tjdests/templates/destinations/student_list.html
Normal file
121
tjdests/templates/destinations/student_list.html
Normal file
|
@ -0,0 +1,121 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% load bootstrap_pagination %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Student Destinations</h2>
|
||||
|
||||
<p><b>Note</b>: All data is self-reported. We do not make any claim as to the accuracy of this data.</p>
|
||||
|
||||
{% if college %}
|
||||
<p>Only showing students reporting applications to {{ college }}.</p>
|
||||
{% endif %}
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Name</th>
|
||||
<th scope="col">Test scores</th>
|
||||
<th scope="col">Biography</th>
|
||||
<th scope="col">Decisions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for senior in object_list %}
|
||||
<tr>
|
||||
<td>{{ senior }}</td>
|
||||
<td>
|
||||
{# Test scores #}
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Test</th>
|
||||
<th scope="col">Score</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for score in senior.testscore_set.all %}
|
||||
<tr>
|
||||
<td>{{ score.get_exam_type_display }}</td>
|
||||
<td>{{ score.exam_score }}</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td>There are no test scores to display.</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
<td>{{ senior.biography|linebreaks }}</td>
|
||||
<td>
|
||||
{# Decisions #}
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Type<br>Result</th>
|
||||
<th scope="col">College Name</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for decision in senior.decision_set.all %}
|
||||
<tr>
|
||||
<td class="d-flex-inline">
|
||||
<span class="justify-content-center d-flex pb-1" data-toggle="tooltip" title="{{ decision.get_decision_type_display }}" aria-label="{{ decision.get_decision_type_display }}">{{ decision.decision_type }}</span>
|
||||
<div class="justify-content-center d-flex">
|
||||
{# First, the waitlist indicator #}
|
||||
{% if decision.admission_status == "WAITLIST" or decision.admission_status == "WAITLIST_ADMIT" or decision.admission_status == "WAITLIST_DENY" %}
|
||||
<i class="fas fa-clipboard-list ps-1" data-toggle="tooltip" title="Waitlisted" aria-label="Waitlisted"></i>
|
||||
{% endif %}
|
||||
{# Now, the deferred indicator #}
|
||||
{% if decision.admission_status == "DEFER" or decision.admission_status == "DEFER_ADMIT" or decision.admission_status == "DEFER_DENY" %}
|
||||
<i class="fas fa-clock ps-1" data-toggle="tooltip" title="Deferred" aria-label="Deferred"></i>
|
||||
{% endif %}
|
||||
{# Admits #}
|
||||
{% if decision.admission_status == "ADMIT" or decision.admission_status == "WAITLIST_ADMIT" or decision.admission_status == "DEFER_ADMIT" %}
|
||||
{# Accepts get a different check #}
|
||||
{% if senior.attending_decision == decision %}
|
||||
<i class="fas fa-check-double ps-1" data-toggle="tooltip" title="Accepted, attending" aria-label="Accepted, attending"></i>
|
||||
{% else %}
|
||||
<i class="fas fa-check ps-1" data-toggle="tooltip" title="Accepted" aria-label="Accepted"></i>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{# Rejects #}
|
||||
{% if decision.admission_status == "DENY" or decision.admission_status == "WAITLIST_DENY" or decision.admission_status == "DEFER_DENY" %}
|
||||
<i class="fas fa-times ps-1" data-toggle="tooltip" title="Denied" aria-label="Denied"></i>
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
<td>{{ decision.college.name }}<br>{{ decision.college.location }}</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td>There are no decisions to display.</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td>There is no data to display.</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="row py-3">
|
||||
<div class="col justify-content-center">
|
||||
{% bootstrap_paginate page_obj range=10 extra_pagination_classes="justify-content-center" %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
20
tjdests/templates/profile/decision_delete.html
Normal file
20
tjdests/templates/profile/decision_delete.html
Normal file
|
@ -0,0 +1,20 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Delete decision</h2>
|
||||
|
||||
<div class="container">
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<p>You are about to delete this decision:</p>
|
||||
|
||||
<p>{{ object.college.name }} {{ object.get_decision_type_display }}</p>
|
||||
|
||||
<input type="submit" value="Confirm" class="btn btn-danger">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
16
tjdests/templates/profile/decision_form.html
Normal file
16
tjdests/templates/profile/decision_form.html
Normal file
|
@ -0,0 +1,16 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Add decision</h2>
|
||||
|
||||
<div class="container">
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{ form|crispy }}
|
||||
<input type="submit" value="Add decision" class="btn btn-primary">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
120
tjdests/templates/profile/profile.html
Normal file
120
tjdests/templates/profile/profile.html
Normal file
|
@ -0,0 +1,120 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Profile</h2>
|
||||
<p>You are {{ request.user.username }}, {{ request.user.first_name }} {{ request.user.last_name }}.</p>
|
||||
|
||||
<h4>Data Publication, College Attending, Biography</h4>
|
||||
<div class="container">
|
||||
{% if request.user.is_senior %}
|
||||
{% crispy profile_form %}
|
||||
{% else %}
|
||||
<p>You are not a senior, so you cannot publish data.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<h4>Decisions</h4>
|
||||
<div class="container">
|
||||
{% if request.user.is_senior %}
|
||||
<div class="pt-3 pb-3">
|
||||
<a href="{% url "profile:decision_add" %}" class="btn btn-outline-primary">Add decision</a>
|
||||
</div>
|
||||
|
||||
<p>Your current decisions are:</p>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">University Name</th>
|
||||
<th scope="col">Admissions Round</th>
|
||||
<th scope="col">Result</th>
|
||||
<th scope="col"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
{% for decision in decisions_list %}
|
||||
<tr>
|
||||
<td>{{ decision.college.name }}</td>
|
||||
<td>{{ decision.get_decision_type_display }}</td>
|
||||
<td>{{ decision.get_admission_status_display }}{% if request.user.attending_decision == decision %}, Attending{% endif %}</td>
|
||||
<td>
|
||||
{# edit button #}
|
||||
<a href="{% url "profile:decision_edit" decision.id %}" class="btn btn-outline-warning" aria-label="Edit">
|
||||
<i class="fas fa-pencil-alt"></i>
|
||||
</a>
|
||||
{# delete #}
|
||||
<a href="{% url "profile:decision_delete" decision.id %}" class="btn btn-outline-danger" aria-label="Delete">
|
||||
<i class="far fa-trash-alt"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td>There is no data to display.</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<p>You are not a senior, therefore you cannot add decisions.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<h4>Test Scores</h4>
|
||||
<div class="container">
|
||||
{% if request.user.is_senior %}
|
||||
<div class="pt-3 pb-3">
|
||||
<a href="{% url "profile:testscores_add" %}" class="btn btn-outline-primary">Add test score</a>
|
||||
</div>
|
||||
|
||||
<p>Your current test scores are:</p>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Exam Type</th>
|
||||
<th scope="col">Exam Score</th>
|
||||
<th scope="col"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
{% for score in test_scores_list %}
|
||||
<tr>
|
||||
<td>{{ score.get_exam_type_display }}</td>
|
||||
<td>{{ score.exam_score }}</td>
|
||||
<td>
|
||||
{# edit button #}
|
||||
<a href="{% url "profile:testscores_edit" score.id %}" class="btn btn-outline-warning" aria-label="Edit">
|
||||
<i class="fas fa-pencil-alt"></i>
|
||||
</a>
|
||||
{# delete #}
|
||||
<a href="{% url "profile:testscores_delete" score.id %}" class="btn btn-outline-danger" aria-label="Delete">
|
||||
<i class="far fa-trash-alt"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td>There is no data to display.</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<p>You are not a senior, therefore you cannot add test scores.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock %}
|
20
tjdests/templates/profile/testscore_delete.html
Normal file
20
tjdests/templates/profile/testscore_delete.html
Normal file
|
@ -0,0 +1,20 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Delete test score</h2>
|
||||
|
||||
<div class="container">
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<p>You are about to delete this test score:</p>
|
||||
|
||||
<p>{{ object.get_exam_type_display }}: {{ object.exam_score }}</p>
|
||||
|
||||
<input type="submit" value="Confirm" class="btn btn-danger">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
16
tjdests/templates/profile/testscore_form.html
Normal file
16
tjdests/templates/profile/testscore_form.html
Normal file
|
@ -0,0 +1,16 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Add test score</h2>
|
||||
|
||||
<div class="container">
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{ form|crispy }}
|
||||
<input type="submit" value="Add test score" class="btn btn-primary">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
25
tjdests/urls.py
Normal file
25
tjdests/urls.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
"""tjdests URL Configuration
|
||||
|
||||
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||
https://docs.djangoproject.com/en/3.2/topics/http/urls/
|
||||
Examples:
|
||||
Function views
|
||||
1. Add an import: from my_app import views
|
||||
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
||||
Class-based views
|
||||
1. Add an import: from other_app.views import Home
|
||||
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
||||
Including another URLconf
|
||||
1. Import the include() function: from django.urls import include, path
|
||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||
"""
|
||||
from django.contrib import admin
|
||||
from django.urls import path, include
|
||||
|
||||
urlpatterns = [
|
||||
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("profile/", include("tjdests.apps.profile.urls", namespace="profile")),
|
||||
]
|
16
tjdests/wsgi.py
Normal file
16
tjdests/wsgi.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
"""
|
||||
WSGI config for tjdests project.
|
||||
|
||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tjdests.settings')
|
||||
|
||||
application = get_wsgi_application()
|
Loading…
Reference in New Issue
Block a user