Compare commits

...

36 commits

Author SHA1 Message Date
497088884e Switched test cmd 2022-08-07 23:38:11 -05:00
7909332fc6 Added test-build script 2022-08-07 23:26:59 -05:00
e8f5472124 Updated docker syntax 2022-08-07 23:18:05 -05:00
ea6c8fd578 Implemented github actions for CI/CD 2022-08-07 23:16:02 -05:00
36796f18f1 Set prod debug to false 2022-08-07 22:49:10 -05:00
86204cbaa2 Fixed dev dockerfile 2022-08-07 22:47:24 -05:00
3828e04892 Fixed test dockerfile 2022-08-07 22:47:18 -05:00
db91a9964a Implemented docker to work for better CI/CD 2022-08-07 22:16:10 -05:00
1fb61abfd2 Added variable settings files 2022-08-07 22:15:53 -05:00
088ce2a9fa Added favicon to site 2022-08-07 14:59:54 -05:00
1305a1e328 Removed static folder 2022-08-07 14:50:23 -05:00
4a5d2b8a22 Decided to nix test suite 2022-05-29 12:01:49 -05:00
72b6e6f703 Updated modified readme links 2022-05-27 23:14:11 -05:00
36654531d5 Created base test file 2022-05-27 23:04:57 -05:00
ed69f75a27 Added .env section to README 2022-05-26 18:44:05 -05:00
3d21fd38a2 Added functionality for test database. 2022-05-26 18:39:24 -05:00
b51639bb64 Modified headers on README.md 2022-05-26 18:14:42 -05:00
494f34e66b Added README with installation and usage instructions 2022-05-26 18:13:23 -05:00
6830a0581f Fixed gitattributes to ignore css 2022-05-22 16:33:03 -05:00
4b65a055cf Removed css files from linguist 2022-05-22 16:30:12 -05:00
3b3756b3f4 Removed static folder from linguist 2022-05-22 16:29:46 -05:00
a4372f2d70 Modified .gitattributes 2022-05-22 16:29:09 -05:00
39770f7078 Created .gitattributes file 2022-05-22 16:27:15 -05:00
c4f02878c1 Organized imports 2022-05-21 15:47:24 -05:00
9e19385a28 Added form to allow incrementation of house points 2022-05-21 15:28:05 -05:00
5a73fecf81 Added House and Points Entry models 2022-05-21 13:51:40 -05:00
e9a4ca1739 Basic styling on all forms 2022-05-19 23:04:00 -05:00
6ff7a0b8d9 Updated project dependencies 2022-05-19 22:01:57 -05:00
c8572bca34 Fixed entry form and display errors 2022-05-19 10:00:28 -05:00
f04e021460 Added deployment settings to settings.py 2022-05-18 10:05:42 -05:00
f88d5b88e3 Generated static files and modified settings.pu 2022-05-18 09:32:18 -05:00
83a3cb74af Added basic styling and modularized templates 2022-05-17 22:47:39 -05:00
567d715fc4 Working model logic and views 2022-05-17 20:47:13 -05:00
e54cb6e7f7 Modified entries to work 2022-05-17 13:48:31 -05:00
d577f0a7e4 Modified admin page for successful signup 2022-05-17 12:35:26 -05:00
bcd0798703 Mutated database tables to have activity1 and activity2 2022-05-17 12:34:18 -05:00
46 changed files with 1496 additions and 85 deletions

1
.dockerignore Normal file
View file

@ -0,0 +1 @@
venv

6
.gitattributes vendored Normal file
View file

@ -0,0 +1,6 @@
*.html linguist-detectable=false
*.js linguist-detectable=false
*.css linguist-detectable=false
static/* linguist-vendored
static/src/*

30
.github/release-drafter.yml vendored Normal file
View file

@ -0,0 +1,30 @@
name-template: 'v$RESOLVED_VERSION'
tag-template: 'v$RESOLVED_VERSION'
categories:
- title: 'Features'
labels:
- 'feature'
- 'enhancement'
- title: 'Bug Fixes'
labels:
- 'fix'
- 'bugfix'
- 'bug'
- title: 'Maintenance'
label: 'chore'
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
change-title-escapes: '\<*_&#@' # You can add # and @ to disable mentions, and add ` to disable code blocks.
version-resolver:
major:
labels:
- 'major'
minor:
labels:
- 'minor'
patch:
labels:
- 'patch'
default: patch
template: |
# Changes
$CHANGES

42
.github/workflows/build-docker.yml vendored Normal file
View file

@ -0,0 +1,42 @@
name: Commit docker image
on:
push:
tags:
- 'v*.*.*'
workflow_dispatch:
jobs:
build:
environment: production
runs-on: ubuntu-latest
steps:
- name: Cache Docker layers
uses: actions/cache@v2
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Checkout
uses: actions/checkout@v2
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
file: ./Dockerfile
builder: ${{ steps.buildx.outputs.name }}
push: true
tags: ${{ secrets.DOCKER_HUB_USERNAME }}/collegiate-housewars:latest
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache
- name: Image digest
run: echo ${{ steps.docker_build.outputs.digest }}

18
.github/workflows/draft-release.yml vendored Normal file
View file

@ -0,0 +1,18 @@
name: Create release draft
on:
push:
branches: [development]
workflow_dispatch:
jobs:
draft:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Draft release
uses: release-drafter/release-drafter@v5
id: release-draft
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

27
.github/workflows/test-build.yml vendored Normal file
View file

@ -0,0 +1,27 @@
name: Test build
on:
push:
branches: [development, main]
pull_request:
workflow_dispatch:
jobs:
test:
environment: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Write .env to build
env:
DOTENV: '${{ secrets.DOTENV }}'
run: echo "$DOTENV" >> .env
- name: Setup python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install dependencies
run: python -m pip install -r requirements.txt
- name: Test build
run: python manage.py test

6
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,6 @@
{
"emmet.includeLanguages": {
"jinja-html": "html"
},
"editor.defaultFormatter": null
}

View file

@ -0,0 +1,3 @@
from . import dev
from . import prod
from . import test

View file

@ -0,0 +1,141 @@
from pathlib import Path
import os
from django.contrib.messages import constants
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
DOTENV_FILE = BASE_DIR / '.env'
SECRET_KEY = os.environ.get('SECRET_KEY')
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
SECURE_SSL_REDIRECT = False
SESSION_COOKIE_SECURE = False
CSRF_COOKIE_SECURE = False
ALLOWED_HOSTS = [
'localhost',
'127.0.0.1',
]
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'formtools',
'housewars.apps.HousewarsConfig'
]
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 = 'CollegiateHouseWars.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',
],
},
},
]
WSGI_APPLICATION = 'CollegiateHouseWars.wsgi.application'
# Database
# https://docs.djangoproject.com/en/4.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'dev',
'USER': os.environ.get('DATABASE_USERNAME'),
'PASSWORD': os.environ.get('DATABASE_PASSWORD'),
'HOST': 'mysqldb',
'PORT': '3306'
}
}
# Password validation
# https://docs.djangoproject.com/en/4.0/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',
},
]
# Internationalization
# https://docs.djangoproject.com/en/4.0/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.0/howto/static-files/
STATIC_URL = 'static/'
STATIC_ROOT = '/var/www/collegiate-housewars/static/'
STATICFILES_DIRS = [
BASE_DIR / "static"
]
# Default primary key field type
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
MESSAGE_TAGS = {constants.DEBUG: 'debug',
constants.INFO: 'info',
constants.SUCCESS: 'success',
constants.WARNING: 'warning',
constants.ERROR: 'danger', }

View file

@ -0,0 +1,141 @@
from pathlib import Path
import os
from django.contrib.messages import constants
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
DOTENV_FILE = BASE_DIR / '.env'
SECRET_KEY = os.environ.get('SECRET_KEY')
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False
SECURE_SSL_REDIRECT = False
SESSION_COOKIE_SECURE = False
CSRF_COOKIE_SECURE = False
ALLOWED_HOSTS = [
'localhost',
'127.0.0.1',
]
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'formtools',
'housewars.apps.HousewarsConfig'
]
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 = 'CollegiateHouseWars.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',
],
},
},
]
WSGI_APPLICATION = 'CollegiateHouseWars.wsgi.application'
# Database
# https://docs.djangoproject.com/en/4.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'prod',
'USER': os.environ.get('DATABASE_USERNAME'),
'PASSWORD': os.environ.get('DATABASE_PASSWORD'),
'HOST': 'mysqldb',
'PORT': '3306'
}
}
# Password validation
# https://docs.djangoproject.com/en/4.0/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',
},
]
# Internationalization
# https://docs.djangoproject.com/en/4.0/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.0/howto/static-files/
STATIC_URL = 'static/'
STATIC_ROOT = '/var/www/housewars/static/'
STATICFILES_DIRS = [
BASE_DIR / "static"
]
# Default primary key field type
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
MESSAGE_TAGS = {constants.DEBUG: 'debug',
constants.INFO: 'info',
constants.SUCCESS: 'success',
constants.WARNING: 'warning',
constants.ERROR: 'danger', }

View file

@ -1,32 +1,28 @@
"""
Django settings for CollegiateHouseWars project.
Generated by 'django-admin startproject' using Django 4.0.4.
For more information on this file, see
https://docs.djangoproject.com/en/4.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.0/ref/settings/
"""
from pathlib import Path
import os
from django.contrib.messages import constants
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
BASE_DIR = Path(__file__).resolve().parent.parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-+m#ore4ojw1s_+yo+kutzpi^asg2dg9+f3+rf(hr#o)73ifo_1'
DOTENV_FILE = BASE_DIR / '.env'
SECRET_KEY = os.environ.get('SECRET_KEY')
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
SECURE_SSL_REDIRECT = False
SESSION_COOKIE_SECURE = False
CSRF_COOKIE_SECURE = False
ALLOWED_HOSTS = [
'localhost',
'127.0.0.1',
]
# Application definition
@ -38,6 +34,8 @@ INSTALLED_APPS = [
'django.contrib.messages',
'django.contrib.staticfiles',
'formtools',
'housewars.apps.HousewarsConfig'
]
@ -56,7 +54,7 @@ ROOT_URLCONF = 'CollegiateHouseWars.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
@ -78,7 +76,7 @@ WSGI_APPLICATION = 'CollegiateHouseWars.wsgi.application'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
'NAME': '/var/www/housewars/db/db.sqlite3',
}
}
@ -118,8 +116,21 @@ USE_TZ = True
# https://docs.djangoproject.com/en/4.0/howto/static-files/
STATIC_URL = 'static/'
STATIC_ROOT = '/var/www/collegiate-housewars/static/'
STATICFILES_DIRS = [
BASE_DIR / "static"
]
# Default primary key field type
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
MESSAGE_TAGS = {constants.DEBUG: 'debug',
constants.INFO: 'info',
constants.SUCCESS: 'success',
constants.WARNING: 'warning',
constants.ERROR: 'danger', }

View file

@ -15,9 +15,11 @@ Including another URLconf
"""
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('', include('housewars.urls')),
path('admin/', admin.site.urls),
]
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

9
Dockerfile Normal file
View file

@ -0,0 +1,9 @@
# syntax=docker/dockerfile:1
FROM python:3.10.6-slim-buster
RUN apt update && apt install build-essential default-libmysqlclient-dev -y
WORKDIR /app
COPY requirements.txt requirements.txt
RUN python -m pip install -r requirements.txt
COPY . .
EXPOSE 8000/tcp
CMD python manage.py runserver 0.0.0.0:8000

50
README.md Normal file
View file

@ -0,0 +1,50 @@
# Collegiate Housewars
Welcome to the repository for the Collegiate School of Medicine and Bioscience Housewars site. This repository is open-source, so feel free to download, play around, or contribute. Below is a guide detailing the basic usage of the site and instructions for installation of a local server. Enjoy!
| Table of Contents |
| ------- |
| [Usage](#Usage-Instructions) |
| [Installation](#Installation) |
| [Defining .env](#Defining-env) |
| [Contributing](#Contributing) |
## Usage Instructions
So far there are three primary pages on this site. They include the:
1. Admin page - this is accessed through `/admin`, and contains the function for managing the activities in the latest housewars and managing points totals and student signups.
2. Student signup form - this is accessed at `/`, and contains the form needed for students to signup for housewars activities.
3. Teacher points form - this is accessed at `/points` and contains the form needed for teachers to add points to houses for activities.
## Installation
Welcome to the installation section of the guide. This will walk you through installing the site and spinning up a local development server.
### Prerequisites:
- git - You can test if you have git installed using the command `git -v`, which should output a version number. If you do not have it installed you can install it [here](https://git-scm.com/downloads).
- python - You can test if you have python installed by typing `python -v` in the terminal. The resulting output should be a version number. If you do not have python installed, you can download it [here](https://www.python.org/downloads/).
- python-pip - Test if you have it installed by typing `python -m pip --version`. You should see a version number for the current version of pip. There are two ways to download it if you do not have it. You can either run the command `python -m ensurepip --upgrade` if your python installation contains the ensurepip module. Otherwise, you will have to download the [get-pip.py](https://bootstrap.pypa.io/get-pip.py) file from online and run that.
- virtualenv - You will need to install virtualenv by using the command `python -m virtualenv <virtualenv name> <root project directory>`.
### Instructions
1. Clone the repository into the desired directory using `git clone https://github.com/C4theBomb/collegiate-housewars.git`
2. Navigate into the repository using `cd collegiate-housewars`
3. Run the command `python -m virtualenv <virtual env name>`, then activate the environment using `./<virtual env name>/Scripts/activate`.
4. Install all the required packages using `pip install -r requirements.txt`.
5. Run migrations and create a development sqlite3 database using `python manage.py migrate`.
6. Server should be available to run. You can activate the server using `python manage.py runserver`. The site will be accessible using the [default url](http://localhost:8000).
## Defining .env
The `.env` file is used to secure data and keep it from entering a cloud, open-acccess environment. Because of this, you will need to define a `.env` file yourself. The parameters that you will need are:
- SECRET_KEY - This will contain the server key of your django local server. It can be generated using the command `python -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())'`.
- DATABASE_USERNAME - This will be the username of your production database.
- DATABASE_PASSWORD - This will be the password of your production database.
- DATABASE_HOST - This will be IPv4/IPv6 address of your production database.
- DATABASE_NAME - This will be the name of your production database.
## Contributing
As an open-source school repository we welcome all contributors willing to help make our website better.
### Instructions
1. Follow the [installation instructions above](#Installation) to install the required packages and run the local server. You will want to fork the repository before cloning it.
2. Commit your new features to your new forked repository.
3. Create a pull request that details the changes/improvements that you have made.
4. Wait for @C4theBomb to open discussion/merge your pull request.

35
docker-compose.prod.yml Normal file
View file

@ -0,0 +1,35 @@
version: '3.8'
name: 'collegiate-housewars'
services:
app:
restart: unless-stopped
build:
context: .
ports:
- 8000:8000
volumes:
- ./:/app
networks:
- housewars
env_file: .env
environment:
DJANGO_SETTINGS_MODULE: "CollegiateHouseWars.settings.prod"
depends_on:
- mysqldb
mysqldb:
restart: unless-stopped
image: mysql:5.7
ports:
- 3306:3306
volumes:
- housewars-mysql:/var/lib/mysql
networks:
- housewars
environment:
MYSQL_ROOT_PASSWORD: "${DATABASE_PASSWORD}"
MYSQL_DATABASE: prod
volumes:
housewars-mysql:
networks:
housewars: {}

18
docker-compose.test.yml Normal file
View file

@ -0,0 +1,18 @@
version: '3.8'
name: 'collegiate-housewars'
services:
app:
build:
context: .
ports:
- 8000:8000
volumes:
- ./:/app
- housewars-sqlite3:/var/www/housewars/db
env_file: .env
environment:
DJANGO_SETTINGS_MODULE: "CollegiateHouseWars.settings.test"
command: python manage.py test
volumes:
housewars-sqlite3:

35
docker-compose.yml Normal file
View file

@ -0,0 +1,35 @@
version: '3.8'
name: 'collegiate-housewars'
services:
app:
restart: unless-stopped
build:
context: .
ports:
- 8000:8000
volumes:
- ./:/app
networks:
- housewars
env_file: .env
environment:
DJANGO_SETTINGS_MODULE: "CollegiateHouseWars.settings.dev"
depends_on:
- mysqldb
mysqldb:
restart: unless-stopped
image: mysql:5.7
ports:
- 3306:3306
volumes:
- housewars-mysql:/var/lib/mysql
networks:
- housewars
environment:
MYSQL_ROOT_PASSWORD: "${DATABASE_PASSWORD}"
MYSQL_DATABASE: dev
volumes:
housewars-mysql:
networks:
housewars: {}

View file

@ -1,6 +1,66 @@
from django.contrib import admin
from .models import Activity, Entry
from django.db.models import Sum
from django.db.models.functions import Coalesce
# Register your models here.
admin.site.register(Activity)
admin.site.register(Entry)
from .models import Activity, House, PointsEntry, UserEntry
@admin.register(Activity)
class ActivityAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['name']}),
('Activity Information', {
'fields': ['quota', 'time']}),
]
list_display = ['name', 'time', 'quota', 'hawk_signups',
'great_grey_signups', 'snowy_signups', 'eagle_signups']
@admin.display(description='Hawk Signups')
def hawk_signups(self, obj):
return str(UserEntry.hawk.filterActivity1(obj).count()) + " / " + str((UserEntry.hawk.filterActivity2(obj).count(), "N/A")[obj.time == 60])
@admin.display(description='Great Grey Signups')
def great_grey_signups(self, obj):
return str(UserEntry.great_grey.filterActivity1(obj).count()) + " / " + str((UserEntry.great_grey.filterActivity2(obj).count(), "N/A")[obj.time == 60])
@admin.display(description='Snowy Signups')
def snowy_signups(self, obj):
return str(UserEntry.snowy.filterActivity1(obj).count()) + " / " + str((UserEntry.snowy.filterActivity2(obj).count(), "N/A")[obj.time == 60])
@admin.display(description='Eagle Signups')
def eagle_signups(self, obj):
return str(UserEntry.eagle.filterActivity1(obj).count()) + " / " + str((UserEntry.eagle.filterActivity2(obj).count(), "N/A")[obj.time == 60])
@admin.register(House)
class HouseAdmin(admin.ModelAdmin):
list_display = ('name', 'points', 'current_points', 'total_points')
@admin.display(description='Current Housewars Points')
def current_points(self, obj):
return PointsEntry.objects.filter(house__name=obj.name).aggregate(points__sum=Coalesce(Sum('points'), 0)).get('points__sum')
@admin.display(description='Total Points')
def total_points(self, obj):
return self.current_points(obj) + obj.points
@admin.register(UserEntry)
class EntryAdmin(admin.ModelAdmin):
fieldsets = [
('Personal Information', {'fields': [
'first_name', 'last_name', 'email', 'grade']}),
('House Wars Information', {
'fields': ['house', 'activity1', 'activity2']}),
]
list_display = ('first_name', 'last_name',
'house', 'activity1', 'activity2')
list_filter = ['house', 'grade', 'activity1', 'activity2']
@admin.register(PointsEntry)
class PointsEntryAdmin(admin.ModelAdmin):
list_display = ('activity', 'name', 'house', 'points')

98
housewars/forms.py Normal file
View file

@ -0,0 +1,98 @@
from django.forms import (CharField, ChoiceField, EmailField, EmailInput, Form,
ModelChoiceField, ModelForm, NumberInput, Select,
Textarea, TextInput, ValidationError)
from .models import Activity, House, PointsEntry, UserEntry
class UserEntryForm(Form):
first_name = CharField(widget=TextInput(attrs={
'class': 'form-control',
'id': 'first-name',
'placeholder': 'First Name'
}))
last_name = CharField(widget=TextInput(attrs={
'class': "form-control",
'id': 'last-name',
'placeholder': 'Last Name'
}))
email = EmailField(widget=EmailInput(attrs={
'class': "form-control",
'id': 'email',
'placeholder': 'Email'
}))
grade = ChoiceField(choices=UserEntry.GradeChoices, widget=Select(attrs={
'class': "form-select",
'id': 'grade',
'placeholder': 'Grade'
}))
house = ModelChoiceField(House.objects.all(), widget=Select(attrs={
'class': "form-select",
'id': 'house',
'placeholder': 'House'
}))
class ActivityForm(Form):
activity1 = ModelChoiceField(Activity.objects.all(), widget=Select(attrs={
'class': "form-select",
'id': 'activity1',
'placeholder': 'Activity 1'
}))
activity2 = ModelChoiceField(Activity.objects.all(), required=False, widget=Select(attrs={
'class': "form-select",
'id': 'activity2',
'placeholder': 'Activity 2'
}))
def clean(self):
data = self.cleaned_data
activity1 = data.get('activity1')
activity2 = data.get('activity2')
if activity1:
if activity2 and activity1.time + activity2.time != 60:
raise ValidationError(
"Please pick activities adding up to one hour.")
elif not activity2 and activity1.time != 60:
raise ValidationError(
"Please pick activities adding up to one hour.")
else:
super().clean()
else:
raise ValidationError("Please select an activity.")
class PointsEntryForm(ModelForm):
class Meta:
model = PointsEntry
fields = '__all__'
widgets = {
'name': TextInput(attrs={
'class': 'form-control',
'id': 'first-name',
'placeholder': 'Full Name'
}),
'activity': Select(attrs={
'class': "form-select",
'id': 'house',
'placeholder': 'Activity'
}),
'house': Select(attrs={
'class': "form-select",
'id': 'house',
'placeholder': 'House'
}),
'points': NumberInput(attrs={
'class': "form-control",
'id': 'last-name',
'placeholder': 'Number of Points'
}),
'comment': Textarea(attrs={
'class': 'form-control',
'id': 'first-name',
'placeholder': 'Comments',
'style': 'height:10vh;'
})
}

29
housewars/managers.py Normal file
View file

@ -0,0 +1,29 @@
from django.db.models import Manager
class EntryManager(Manager):
def filterActivity1(self, act):
return self.filter(activity1=act)
def filterActivity2(self, act):
return self.filter(activity2=act)
class HawkEntryManager(EntryManager):
def get_queryset(self):
return super().get_queryset().filter(house__name='Hawk')
class EagleEntryManager(EntryManager):
def get_queryset(self):
return super().get_queryset().filter(house__name='Eagle')
class GreatGreyEntryManager(EntryManager):
def get_queryset(self):
return super().get_queryset().filter(house__name='Great Grey')
class SnowyEntryManager(EntryManager):
def get_queryset(self):
return super().get_queryset().filter(house__name='Snowy')

View file

@ -0,0 +1,19 @@
# Generated by Django 4.0.4 on 2022-05-17 12:43
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('housewars', '0004_alter_entry_grade'),
]
operations = [
migrations.AlterField(
model_name='entry',
name='activity2',
field=models.ForeignKey(blank=True, on_delete=django.db.models.deletion.CASCADE, related_name='activity2', to='housewars.activity'),
),
]

View file

@ -0,0 +1,19 @@
# Generated by Django 4.0.4 on 2022-05-17 13:09
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('housewars', '0005_alter_entry_activity2'),
]
operations = [
migrations.AddField(
model_name='entry',
name='house',
field=models.CharField(choices=[('HAWK', 'Hawk'), ('GREATGREY', 'Great Grey'), ('EAGLE', 'Eagle'), ('SNOWY', 'Snowy')], default='HAWK', max_length=15),
preserve_default=False,
),
]

View file

@ -0,0 +1,19 @@
# Generated by Django 4.0.4 on 2022-05-17 14:28
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('housewars', '0006_entry_house'),
]
operations = [
migrations.AlterField(
model_name='entry',
name='activity2',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='activity2', to='housewars.activity'),
),
]

View file

@ -0,0 +1,25 @@
# Generated by Django 4.0.4 on 2022-05-17 15:17
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('housewars', '0007_alter_entry_activity2'),
]
operations = [
migrations.AddField(
model_name='activity',
name='session1_signups',
field=models.IntegerField(default=10),
preserve_default=False,
),
migrations.AddField(
model_name='activity',
name='session2_signups',
field=models.IntegerField(default=10),
preserve_default=False,
),
]

View file

@ -0,0 +1,23 @@
# Generated by Django 4.0.4 on 2022-05-17 15:19
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('housewars', '0008_activity_session1_signups_activity_session2_signups'),
]
operations = [
migrations.AlterField(
model_name='activity',
name='session1_signups',
field=models.IntegerField(default=0),
),
migrations.AlterField(
model_name='activity',
name='session2_signups',
field=models.IntegerField(default=0),
),
]

View file

@ -0,0 +1,21 @@
# Generated by Django 4.0.4 on 2022-05-17 22:36
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('housewars', '0009_alter_activity_session1_signups_and_more'),
]
operations = [
migrations.RemoveField(
model_name='activity',
name='session1_signups',
),
migrations.RemoveField(
model_name='activity',
name='session2_signups',
),
]

View file

@ -0,0 +1,33 @@
# Generated by Django 4.0.4 on 2022-05-18 22:10
from django.db import migrations, models
import django.db.models.deletion
import django.db.models.manager
class Migration(migrations.Migration):
dependencies = [
('housewars', '0010_remove_activity_session1_signups_and_more'),
]
operations = [
migrations.CreateModel(
name='House',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
],
),
migrations.AlterModelManagers(
name='activity',
managers=[
('session1', django.db.models.manager.Manager()),
],
),
migrations.AlterField(
model_name='entry',
name='house',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='housewars.house'),
),
]

View file

@ -0,0 +1,26 @@
# Generated by Django 4.0.4 on 2022-05-19 00:21
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('housewars', '0011_house_alter_activity_managers_alter_entry_house'),
]
operations = [
migrations.AlterModelManagers(
name='activity',
managers=[
],
),
migrations.AlterField(
model_name='entry',
name='house',
field=models.CharField(choices=[('HAWK', 'Hawk'), ('GREATGREY', 'Great Grey'), ('EAGLE', 'Eagle'), ('SNOWY', 'Snowy')], max_length=15),
),
migrations.DeleteModel(
name='House',
),
]

View file

@ -0,0 +1,59 @@
# Generated by Django 4.0.4 on 2022-05-21 18:15
from django.db import migrations, models
import django.db.models.deletion
import django.db.models.manager
class Migration(migrations.Migration):
dependencies = [
('housewars', '0012_alter_activity_managers_alter_entry_house_and_more'),
]
operations = [
migrations.CreateModel(
name='House',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
('points', models.IntegerField()),
],
),
migrations.CreateModel(
name='PointsEntry',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
('points', models.IntegerField()),
('reason', models.TextField()),
('activity', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='housewars.activity')),
('house', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='housewars.house')),
],
options={
'verbose_name_plural': 'Point Entries',
},
),
migrations.CreateModel(
name='UserEntry',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('first_name', models.CharField(max_length=100)),
('last_name', models.CharField(max_length=100)),
('email', models.EmailField(max_length=100)),
('grade', models.IntegerField(choices=[(9, '9th/Freshman'), (10, '10th/Sophomore'), (11, '11th/Junior'), (12, '12th/Senior')])),
('activity1', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='activity1', to='housewars.activity')),
('activity2', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='activity2', to='housewars.activity')),
('house', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='housewars.house')),
],
options={
'verbose_name_plural': 'User Entries',
},
managers=[
('hawk', django.db.models.manager.Manager()),
],
),
migrations.DeleteModel(
name='Entry',
),
]

View file

@ -0,0 +1,20 @@
# Generated by Django 4.0.4 on 2022-05-21 18:17
from django.db import migrations
import django.db.models.manager
class Migration(migrations.Migration):
dependencies = [
('housewars', '0013_house_pointsentry_userentry_delete_entry'),
]
operations = [
migrations.AlterModelManagers(
name='pointsentry',
managers=[
('hawk', django.db.models.manager.Manager()),
],
),
]

View file

@ -0,0 +1,18 @@
# Generated by Django 4.0.4 on 2022-05-21 18:33
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('housewars', '0014_alter_pointsentry_managers'),
]
operations = [
migrations.AlterModelManagers(
name='pointsentry',
managers=[
],
),
]

View file

@ -0,0 +1,23 @@
# Generated by Django 4.0.4 on 2022-05-21 20:18
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('housewars', '0015_alter_pointsentry_managers'),
]
operations = [
migrations.AlterModelManagers(
name='userentry',
managers=[
],
),
migrations.RenameField(
model_name='pointsentry',
old_name='reason',
new_name='comment',
),
]

View file

@ -0,0 +1,23 @@
# Generated by Django 4.0.4 on 2022-05-21 20:31
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('housewars', '0016_alter_userentry_managers_and_more'),
]
operations = [
migrations.AlterField(
model_name='house',
name='points',
field=models.IntegerField(default=0),
),
migrations.AlterField(
model_name='pointsentry',
name='points',
field=models.IntegerField(default=0),
),
]

View file

@ -1,7 +1,7 @@
from django.db import models
from django.forms import ValidationError
# Create your models here.
from .managers import (EagleEntryManager, EntryManager, GreatGreyEntryManager,
HawkEntryManager, SnowyEntryManager)
class Activity(models.Model):
@ -21,9 +21,23 @@ class Activity(models.Model):
return f"{self.name} ({self.time})"
class Entry(models.Model):
class House(models.Model):
name = models.CharField(max_length=100)
points = models.IntegerField(default=0)
def __str__(self):
return f"{self.name}"
class UserEntry(models.Model):
class Meta:
verbose_name_plural = "Entries"
verbose_name_plural = "User Entries"
objects = EntryManager()
hawk = HawkEntryManager()
great_grey = GreatGreyEntryManager()
snowy = SnowyEntryManager()
eagle = EagleEntryManager()
GradeChoices = (
(9, '9th/Freshman'),
@ -36,17 +50,23 @@ class Entry(models.Model):
last_name = models.CharField(max_length=100)
email = models.EmailField(max_length=100)
grade = models.IntegerField(choices=GradeChoices)
house = models.ForeignKey(
House, on_delete=models.CASCADE)
activity1 = models.ForeignKey(
Activity, related_name='activity1', on_delete=models.CASCADE)
activity2 = models.ForeignKey(
Activity, related_name='activity2', on_delete=models.CASCADE)
def clean(self):
if self.activity1.time + self.activity2.time > 60:
raise ValidationError(
"Please only pick activities adding up to one hour.")
else:
super().clean()
Activity, related_name='activity2', on_delete=models.CASCADE, blank=True, null=True)
def __str__(self):
return f"{self.first_name} {self.last_name}"
class PointsEntry(models.Model):
class Meta:
verbose_name_plural = "Point Entries"
name = models.CharField(max_length=100)
activity = models.ForeignKey(Activity, on_delete=models.CASCADE)
house = models.ForeignKey(House, on_delete=models.CASCADE)
points = models.IntegerField(default=0)
comment = models.TextField(blank=False)

View file

@ -0,0 +1,62 @@
html, body {
height: 100%;
margin: 0px;
}
.btn-50 {
width: 50%;
}
.btn-100 {
width: 100%;
}
.max-height {
height: 100%;
}
.steps-form {
display: table;
width: 100%;
position: relative;
}
.steps-form .steps-row {
display: table-row;
}
.steps-form .steps-row:before {
top: 14px;
bottom: 0;
position: absolute;
content: " ";
width: 100%;
height: 1px;
background-color: #ccc;
}
.steps-form .steps-row .steps-step {
display: table-cell;
text-align: center;
position: relative;
}
.steps-form .steps-row .steps-step p {
margin-top: 0.5rem;
}
.steps-form .steps-row .steps-step button[disabled] {
opacity: 1 !important;
filter: alpha(opacity=100) !important;
}
.steps-form .steps-row .steps-step .btn-circle {
width: 30px;
height: 30px;
text-align: center;
padding: 6px 0;
font-size: 12px;
line-height: 1.428571429;
border-radius: 15px;
margin-top: 0;
}

View file

@ -0,0 +1,54 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}
<title>House Wars - Signup</title>
{% endblock %}
{% block formtitle %}
<h1 class="text-center mt-1 mb-4">Signup</h1>
{% endblock %}
{% block content %}
<form method="POST">
{% csrf_token %}
{{ wizard.management_form }}
<div class="steps-form">
<div class="steps-row setup-panel">
<div class="steps-step">
<button name="wizard_goto_step" class="btn btn-secondary btn-circle" type="submit" value="user">1</button>
<p>Student Information</p>
</div>
<div class="steps-step">
<button name="wizard_goto_step" class="btn btn-primary btn-circle" type="disabled"
value="activity">2</button>
<p>Activity Information</p>
</div>
</div>
</div>
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags }}">
{{ message }}
</div>
{% endfor %}
{% endif %}
<div class="mb-3">
<label for="activity1" class="form-label">Activity 1:</label>
{{ form.activity1 }}
</div>
<div class="mb-3">
<label for="activity2" class="form-label">Activity 2:</label>
{{ form.activity2 }}
</div>
<div class="form-group d-flex justify-content-center">
<button name="wizard_goto_step" class="btn btn-outline-primary btn-50" type="submit" value="{{ wizard.steps.prev }}">Previous Step</button>
<input class="btn btn-outline-primary btn-50" type="submit" value="Submit" />
</div>
</form>
{% endblock %}

View file

@ -1,42 +1,64 @@
<html>
<head>
<meta charset="ISO-8859-1" />
<meta name="description" content="A website made by C4 Patino" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-+0n0xVW2eSR5OomGNYDnhzAbDsOXxcvSN1TPprVMTNDbiYZCxYbOOl7+AMvyTG2x"
crossorigin="anonymous"
/>
{% extends 'base.html' %}
{% load i18n %}
{% if title %}
<title>Django Blog - {{title}}</title>
{% else %}
<title>Django Blog</title>
{% endif %}
</head>
<body>
<main role="main" class="container">
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Blog Post</legend>
{{ form }}
</fieldset>
<div>
<button class="btn btn-outline-info" type="submit">
Post
</button>
</div>
</form>
{% block title %}
<title>House Wars - Signup</title>
{% endblock %}
{% block formtitle %}
<h1 class="text-center mt-1 mb-4">Signup</h1>
{% endblock %}
{% block content %}
<form method="POST">
{% csrf_token %}
{{ wizard.management_form }}
<div class="steps-form">
<div class="steps-row setup-panel">
<div class="steps-step">
<button name="wizard_goto_step" class="btn btn-primary btn-circle" type="disabled" value="user">1</button>
<p>Student Information</p>
</div>
<div class="steps-step">
<button name="wizard_goto_step" class="btn btn-secondary btn-circle" type="submit"
value="activity">2</button>
<p>Activity Information</p>
</div>
</div>
</main>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-gtEjrD/SeCtmISkJkNUaaKMoLD0//ElJ19smozuHV6z3Iehds+3Ulb9Bn9Plx0x4"
crossorigin="anonymous"
></script>
</body>
</html>
</div>
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags }}">
{{ message }}
</div>
{% endfor %}
{% endif %}
<label for="name" class="form-label">Name:</label>
<div class="row mb-3" id="name">
<div class="col">
{{ form.first_name }}
</div>
<div class="col">
{{ form.last_name }}
</div>
</div>
<div class="mb-3">
<label for="email" class="form-label">Email:</label>
{{ form.email }}
</div>
<div class="mb-3">
<label for="grade" class="form-label">Grade:</label>
{{ form.grade }}
</div>
<div class="mb-3">
<label for="house" class="form-label">House:</label>
{{ form.house }}
</div>
<div class="form-group d-flex justify-content-center">
<input class="btn btn-outline-primary btn-100" type="submit" value="Submit" />
</div>
</form>
{% endblock %}

View file

@ -0,0 +1,50 @@
{% extends 'base.html' %}
{% block title %}
<title>House Wars - Add House Points</title>
{% endblock %}
{% block formtitle %}
<h1 class="text-center mt-1 mb-4">Add House Points</h1>
{% endblock %}
{% block content %}
<form method="POST">
{% csrf_token %}
<div class="mb-3">
<label for="name" class="name">Name:</label>
{{ form.name }}
</div>
<div class="mb-3">
<label for="activity" class="form-label">Activity:</label>
{{ form.activity }}
</div>
<div class="mb-3">
<label for="house" class="form-label">House:</label>
{{ form.house }}
</div>
<div class="mb-3">
<label for="points" class="form-label">Points:</label>
{{ form.points }}
</div>
<div class="mb-3">
<label for="comment" class="form-label">Comments:</label>
{{ form.comment }}
</div>
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags }}">
{{ message }}
</div>
{% endfor %}
{% endif %}
<div class="form-group d-flex justify-content-center">
<input class="btn btn-outline-primary btn-100" type="submit" value="Submit" />
</div>
</form>
{% endblock %}

View file

@ -1,3 +1 @@
from django.test import TestCase
# Create your tests here.

View file

@ -14,11 +14,12 @@ Including another URLconf
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
from django.urls import path
from . import views
app_name = 'housewars'
urlpatterns = [
path('', views.EntryCreateView.as_view(), name='entry_create'),
path('', views.EntryCreateView.as_view(), name='signup'),
path('points/', views.CreatePointsEntry.as_view(), name='add_points')
]

View file

@ -1,10 +1,65 @@
from django.shortcuts import render
from django.contrib import messages
from django.db.models import Count, F, Q
from django.shortcuts import redirect
from django.urls import reverse
from django.views.generic import CreateView
from formtools.wizard.views import SessionWizardView
from .models import Entry
from .forms import ActivityForm, PointsEntryForm, UserEntryForm
from .models import Activity, PointsEntry, UserEntry
FORMS = [("user", UserEntryForm),
("activity", ActivityForm)]
TEMPLATES = {"user": "housewars/entry_form.html",
"activity": "housewars/activity_form.html"}
class EntryCreateView(CreateView):
model = Entry
fields = ['first_name', 'last_name', 'email',
'grade', 'activity1', 'activity2']
class EntryCreateView(SessionWizardView):
form_list = FORMS
def get_template_names(self):
return [TEMPLATES[self.steps.current]]
def post(self, *args, **kwargs):
form = self.get_form(data=self.request.POST, files=self.request.FILES)
if not form.is_valid():
if (form.errors.as_data().get('__all__')):
for error in form.errors.as_data().get('__all__'):
messages.error(self.request, error.messages[0])
return super().post(*args, **kwargs)
def get_form(self, step=None, data=None, files=None):
form = super().get_form(step, data, files)
if step == 'activity':
cd = self.storage.get_step_data('user')
filtered1 = Activity.objects.annotate(count=Count(
'activity1', filter=Q(activity1__house=cd.get('user-house')))).filter(quota__gt=F('count'))
filtered2 = Activity.objects.annotate(count=Count(
'activity2', filter=Q(activity2__house=cd.get('user-house')))).filter(quota__gt=F('count'), time=30)
form.fields['activity1'].queryset = filtered1
form.fields['activity2'].queryset = filtered2
return form
def done(self, form_list, **kwargs):
UserEntry.objects.create(**self.get_all_cleaned_data())
messages.success(self.request, 'Your entry has been submitted')
return redirect('housewars:signup')
def get_success_url(self):
return reverse('housewars:signup')
class CreatePointsEntry(CreateView):
model = PointsEntry
form_class = PointsEntryForm
def get_success_url(self):
return reverse('housewars:add_points')

View file

@ -3,10 +3,16 @@
import os
import sys
from dotenv import load_dotenv
from pathlib import Path
load_dotenv(Path('.env'))
def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'CollegiateHouseWars.settings')
os.environ.setdefault('DJANGO_SETTINGS_MODULE',
'CollegiateHouseWars.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:

Binary file not shown.

BIN
static/favicon.ico vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -0,0 +1,18 @@
{% extends "admin/base_site.html" %}
{% block title %}
{% if subtitle %}
{{ subtitle }} |
{% endif %}
{{ title }} |
{{ site_title|default:_('Djangosite admin') }}
{% endblock %}
{% block branding %}
<h1 id="site-name">
<a href="{% url 'admin:index' %}">House Wars Admin Page</a>
</h1>
{% endblock %}
{% block nav-global %}
{% endblock %}

35
templates/base.html Normal file
View file

@ -0,0 +1,35 @@
{% load static %}
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1" />
<meta name="description" content="A website made by C4 Patino" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href='{% static "css/main.css" %}' />
<link rel="icon" type="image/x-icon" href='{% static "favicon.ico" %}'>
{% block title %}
<title>House Wars</title>
{% endblock %}
</head>
<body>
<main role="main" class="container max-height">
<div class="row d-flex justify-content-center align-items-center max-height">
<div class="card col-md-5 p-4 m-3">
{% block formtitle %}
<h1 class="text-center mt-1 mb-4">House Wars</h1>
{% endblock %}
<!-- Main content -->
{% block content %}{% endblock %}
</div>
</div>
</main>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-gtEjrD/SeCtmISkJkNUaaKMoLD0//ElJ19smozuHV6z3Iehds+3Ulb9Bn9Plx0x4"
crossorigin="anonymous"
></script>
</body>
</html>