@ -0,0 +1 @@ | |||||
__pycache__/ |
@ -0,0 +1,3 @@ | |||||
from django.contrib import admin | |||||
# Register your models here. |
@ -0,0 +1,5 @@ | |||||
from django import forms | |||||
class EmailForm(forms.Form): | |||||
email = forms.EmailField() |
@ -0,0 +1,3 @@ | |||||
from django.db import models | |||||
# Create your models here. |
@ -0,0 +1,3 @@ | |||||
from django.test import TestCase | |||||
# Create your tests here. |
@ -0,0 +1,9 @@ | |||||
from django.conf.urls import url | |||||
from hc.accounts import views | |||||
urlpatterns = [ | |||||
url(r'^login/$', views.login, name="hc-login"), | |||||
url(r'^login_link_sent/$', views.login_link_sent, name="hc-login-link-sent"), | |||||
url(r'^check_token/([\w-]+)/$', views.check_token, name="hc-check-token"), | |||||
] |
@ -0,0 +1,49 @@ | |||||
import uuid | |||||
from django.conf import settings | |||||
from django.contrib.auth.models import User | |||||
from django.core.mail import send_mail | |||||
from django.core.urlresolvers import reverse | |||||
from django.shortcuts import redirect, render | |||||
from hc.accounts.forms import EmailForm | |||||
def login(request): | |||||
if request.method == 'POST': | |||||
# create a form instance and populate it with data from the request: | |||||
form = EmailForm(request.POST) | |||||
# check whether it's valid: | |||||
if form.is_valid(): | |||||
email = form.cleaned_data["email"] | |||||
user = User.objects.get(email=email) | |||||
token = str(uuid.uuid4()) | |||||
user.set_password(token) | |||||
user.save() | |||||
login_link = reverse("hc-check-token", args=[token]) | |||||
login_link = settings.SITE_ROOT + login_link | |||||
body = "login link: %s" % login_link | |||||
send_mail('Log In', body, '[email protected]', [email], fail_silently=False) | |||||
# FIXME send login token here | |||||
return redirect("hc-login-link-sent") | |||||
else: | |||||
form = EmailForm() | |||||
ctx = { | |||||
"form": form | |||||
} | |||||
return render(request, "accounts/login.html", ctx) | |||||
def login_link_sent(request): | |||||
return render(request, "accounts/login_link_sent.html") | |||||
def check_token(request): | |||||
return render(request, "accounts/login_link_sent.html") |
@ -0,0 +1,8 @@ | |||||
from django.contrib import admin | |||||
from hc.checks.models import Canary | |||||
@admin.register(Canary) | |||||
class CanaryAdmin(admin.ModelAdmin): | |||||
list_display = ("id", "code", "user", "last_ping") |
@ -0,0 +1,24 @@ | |||||
# -*- coding: utf-8 -*- | |||||
from __future__ import unicode_literals | |||||
from django.db import models, migrations | |||||
import uuid | |||||
from django.conf import settings | |||||
class Migration(migrations.Migration): | |||||
dependencies = [ | |||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL), | |||||
] | |||||
operations = [ | |||||
migrations.CreateModel( | |||||
name='Canary', | |||||
fields=[ | |||||
('id', models.AutoField(auto_created=True, serialize=False, primary_key=True, verbose_name='ID')), | |||||
('code', models.UUIDField(default=uuid.uuid4, editable=False)), | |||||
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)), | |||||
], | |||||
), | |||||
] |
@ -0,0 +1,23 @@ | |||||
# -*- coding: utf-8 -*- | |||||
from __future__ import unicode_literals | |||||
from django.db import models, migrations | |||||
class Migration(migrations.Migration): | |||||
dependencies = [ | |||||
('checks', '0001_initial'), | |||||
] | |||||
operations = [ | |||||
migrations.AlterModelOptions( | |||||
name='canary', | |||||
options={'verbose_name_plural': 'canaries'}, | |||||
), | |||||
migrations.AddField( | |||||
model_name='canary', | |||||
name='last_ping', | |||||
field=models.DateTimeField(null=True, blank=True), | |||||
), | |||||
] |
@ -0,0 +1,13 @@ | |||||
import uuid | |||||
from django.contrib.auth.models import User | |||||
from django.db import models | |||||
class Canary(models.Model): | |||||
class Meta: | |||||
verbose_name_plural = "canaries" | |||||
code = models.UUIDField(default=uuid.uuid4, editable=False) | |||||
user = models.ForeignKey(User) | |||||
last_ping = models.DateTimeField(null=True, blank=True) |
@ -0,0 +1,3 @@ | |||||
from django.test import TestCase | |||||
# Create your tests here. |
@ -0,0 +1,7 @@ | |||||
from django.conf.urls import url | |||||
from hc.checks import views | |||||
urlpatterns = [ | |||||
url(r'^ping/([\w-]+)/$', views.ping, name="hc-ping"), | |||||
] |
@ -0,0 +1,16 @@ | |||||
from django.http import HttpResponse, HttpResponseBadRequest | |||||
from django.utils import timezone | |||||
from hc.checks.models import Canary | |||||
def ping(request, code): | |||||
try: | |||||
canary = Canary.objects.get(code=code) | |||||
except Canary.DoesNotExist: | |||||
return HttpResponseBadRequest() | |||||
canary.last_ping = timezone.now() | |||||
canary.save() | |||||
return HttpResponse() |
@ -0,0 +1,111 @@ | |||||
""" | |||||
Django settings for hc project. | |||||
Generated by 'django-admin startproject' using Django 1.8.2. | |||||
For more information on this file, see | |||||
https://docs.djangoproject.com/en/1.8/topics/settings/ | |||||
For the full list of settings and their values, see | |||||
https://docs.djangoproject.com/en/1.8/ref/settings/ | |||||
""" | |||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) | |||||
import os | |||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | |||||
# Quick-start development settings - unsuitable for production | |||||
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/ | |||||
# SECURITY WARNING: keep the secret key used in production secret! | |||||
SECRET_KEY = '9)gjy!j50uvbcy#y9ifoh@9pf%3m5^-9h0jv@+3^ln$%az8e(7' | |||||
# 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', | |||||
'bootstrap3', | |||||
'hc.accounts', | |||||
'hc.checks' | |||||
) | |||||
MIDDLEWARE_CLASSES = ( | |||||
'django.contrib.sessions.middleware.SessionMiddleware', | |||||
'django.middleware.common.CommonMiddleware', | |||||
'django.middleware.csrf.CsrfViewMiddleware', | |||||
'django.contrib.auth.middleware.AuthenticationMiddleware', | |||||
'django.contrib.auth.middleware.SessionAuthenticationMiddleware', | |||||
'django.contrib.messages.middleware.MessageMiddleware', | |||||
'django.middleware.clickjacking.XFrameOptionsMiddleware', | |||||
'django.middleware.security.SecurityMiddleware', | |||||
) | |||||
ROOT_URLCONF = 'hc.urls' | |||||
TEMPLATES = [ | |||||
{ | |||||
'BACKEND': 'django.template.backends.django.DjangoTemplates', | |||||
'DIRS': [os.path.join(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 = 'hc.wsgi.application' | |||||
# Database | |||||
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases | |||||
DATABASES = { | |||||
'default': { | |||||
'ENGINE': 'django.db.backends.postgresql_psycopg2', | |||||
'NAME': 'hc', | |||||
'USER': 'hc', | |||||
'PASSWORD': '', | |||||
'HOST': '192.168.1.111', | |||||
'PORT': 5432, | |||||
'TEST': {'CHARSET': 'UTF8'} | |||||
} | |||||
} | |||||
# Internationalization | |||||
# https://docs.djangoproject.com/en/1.8/topics/i18n/ | |||||
LANGUAGE_CODE = 'en-us' | |||||
TIME_ZONE = 'UTC' | |||||
USE_I18N = True | |||||
USE_L10N = True | |||||
USE_TZ = True | |||||
SITE_ROOT = "http://localhost:8000" | |||||
STATIC_URL = '/static/' | |||||
STATICFILES_DIRS = [os.path.join(BASE_DIR, "static")] |
@ -0,0 +1,8 @@ | |||||
from django.conf.urls import include, url | |||||
from django.contrib import admin | |||||
urlpatterns = [ | |||||
url(r'^admin/', include(admin.site.urls)), | |||||
url(r'^accounts/', include('hc.accounts.urls')), | |||||
url(r'^', include('hc.checks.urls')), | |||||
] |
@ -0,0 +1,16 @@ | |||||
""" | |||||
WSGI config for hc 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/1.8/howto/deployment/wsgi/ | |||||
""" | |||||
import os | |||||
from django.core.wsgi import get_wsgi_application | |||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "hc.settings") | |||||
application = get_wsgi_application() |
@ -0,0 +1,10 @@ | |||||
#!/usr/bin/env python | |||||
import os | |||||
import sys | |||||
if __name__ == "__main__": | |||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "hc.settings") | |||||
from django.core.management import execute_from_command_line | |||||
execute_from_command_line(sys.argv) |
@ -0,0 +1,3 @@ | |||||
Django==1.8.2 | |||||
django-bootstrap3 | |||||
psycopg2==2.6 |
@ -0,0 +1,476 @@ | |||||
/*! | |||||
* Start Bootstrap - Creative Bootstrap Theme (http://startbootstrap.com) | |||||
* Code licensed under the Apache License v2.0. | |||||
* For details, see http://www.apache.org/licenses/LICENSE-2.0. | |||||
*/ | |||||
html, | |||||
body { | |||||
width: 100%; | |||||
height: 100%; | |||||
} | |||||
body { | |||||
font-family: Merriweather,'Helvetica Neue',Arial,sans-serif; | |||||
} | |||||
hr { | |||||
max-width: 50px; | |||||
border-color: #f05f40; | |||||
border-width: 3px; | |||||
} | |||||
hr.light { | |||||
border-color: #fff; | |||||
} | |||||
a { | |||||
color: #f05f40; | |||||
-webkit-transition: all .35s; | |||||
-moz-transition: all .35s; | |||||
transition: all .35s; | |||||
} | |||||
a:hover, | |||||
a:focus { | |||||
color: #eb3812; | |||||
} | |||||
h1, | |||||
h2, | |||||
h3, | |||||
h4, | |||||
h5, | |||||
h6 { | |||||
font-family: 'Open Sans','Helvetica Neue',Arial,sans-serif; | |||||
} | |||||
p { | |||||
margin-bottom: 20px; | |||||
font-size: 16px; | |||||
line-height: 1.5; | |||||
} | |||||
.bg-primary { | |||||
background-color: #f05f40; | |||||
} | |||||
.bg-dark { | |||||
color: #fff; | |||||
background-color: #222; | |||||
} | |||||
.text-faded { | |||||
color: rgba(255,255,255,.7); | |||||
} | |||||
section { | |||||
padding: 100px 0; | |||||
} | |||||
aside { | |||||
padding: 50px 0; | |||||
} | |||||
.no-padding { | |||||
padding: 0; | |||||
} | |||||
.navbar-default { | |||||
border-color: rgba(34,34,34,.05); | |||||
font-family: 'Open Sans','Helvetica Neue',Arial,sans-serif; | |||||
background-color: #fff; | |||||
-webkit-transition: all .35s; | |||||
-moz-transition: all .35s; | |||||
transition: all .35s; | |||||
} | |||||
.navbar-default .navbar-header .navbar-brand { | |||||
text-transform: uppercase; | |||||
font-family: 'Open Sans','Helvetica Neue',Arial,sans-serif; | |||||
font-weight: 700; | |||||
color: #f05f40; | |||||
} | |||||
.navbar-default .navbar-header .navbar-brand:hover, | |||||
.navbar-default .navbar-header .navbar-brand:focus { | |||||
color: #eb3812; | |||||
} | |||||
.navbar-default .nav > li>a, | |||||
.navbar-default .nav>li>a:focus { | |||||
text-transform: uppercase; | |||||
font-size: 13px; | |||||
font-weight: 700; | |||||
color: #222; | |||||
} | |||||
.navbar-default .nav > li>a:hover, | |||||
.navbar-default .nav>li>a:focus:hover { | |||||
color: #f05f40; | |||||
} | |||||
.navbar-default .nav > li.active>a, | |||||
.navbar-default .nav>li.active>a:focus { | |||||
color: #f05f40!important; | |||||
background-color: transparent; | |||||
} | |||||
.navbar-default .nav > li.active>a:hover, | |||||
.navbar-default .nav>li.active>a:focus:hover { | |||||
background-color: transparent; | |||||
} | |||||
@media(min-width:768px) { | |||||
.navbar-default { | |||||
border-color: rgba(255,255,255,.3); | |||||
background-color: transparent; | |||||
} | |||||
.navbar-default .navbar-header .navbar-brand { | |||||
color: rgba(255,255,255,.7); | |||||
} | |||||
.navbar-default .navbar-header .navbar-brand:hover, | |||||
.navbar-default .navbar-header .navbar-brand:focus { | |||||
color: #fff; | |||||
} | |||||
.navbar-default .nav > li>a, | |||||
.navbar-default .nav>li>a:focus { | |||||
color: rgba(255,255,255,.7); | |||||
} | |||||
.navbar-default .nav > li>a:hover, | |||||
.navbar-default .nav>li>a:focus:hover { | |||||
color: #fff; | |||||
} | |||||
.navbar-default.affix { | |||||
border-color: rgba(34,34,34,.05); | |||||
background-color: #fff; | |||||
} | |||||
.navbar-default.affix .navbar-header .navbar-brand { | |||||
font-size: 14px; | |||||
color: #f05f40; | |||||
} | |||||
.navbar-default.affix .navbar-header .navbar-brand:hover, | |||||
.navbar-default.affix .navbar-header .navbar-brand:focus { | |||||
color: #eb3812; | |||||
} | |||||
.navbar-default.affix .nav > li>a, | |||||
.navbar-default.affix .nav>li>a:focus { | |||||
color: #222; | |||||
} | |||||
.navbar-default.affix .nav > li>a:hover, | |||||
.navbar-default.affix .nav>li>a:focus:hover { | |||||
color: #f05f40; | |||||
} | |||||
} | |||||
header { | |||||
position: relative; | |||||
width: 100%; | |||||
min-height: auto; | |||||
text-align: center; | |||||
color: #fff; | |||||
background-image: url(../img/header.jpg); | |||||
background-position: center; | |||||
-webkit-background-size: cover; | |||||
-moz-background-size: cover; | |||||
background-size: cover; | |||||
-o-background-size: cover; | |||||
} | |||||
header .header-content { | |||||
position: relative; | |||||
width: 100%; | |||||
padding: 100px 15px; | |||||
text-align: center; | |||||
} | |||||
header .header-content .header-content-inner h1 { | |||||
margin-top: 0; | |||||
margin-bottom: 0; | |||||
text-transform: uppercase; | |||||
font-weight: 700; | |||||
} | |||||
header .header-content .header-content-inner hr { | |||||
margin: 30px auto; | |||||
} | |||||
header .header-content .header-content-inner p { | |||||
margin-bottom: 50px; | |||||
font-size: 16px; | |||||
font-weight: 300; | |||||
color: rgba(255,255,255,.7); | |||||
} | |||||
@media(min-width:768px) { | |||||
header { | |||||
min-height: 100%; | |||||
} | |||||
header .header-content { | |||||
position: absolute; | |||||
top: 50%; | |||||
padding: 0 50px; | |||||
-webkit-transform: translateY(-50%); | |||||
-ms-transform: translateY(-50%); | |||||
transform: translateY(-50%); | |||||
} | |||||
header .header-content .header-content-inner { | |||||
margin-right: auto; | |||||
margin-left: auto; | |||||
max-width: 1000px; | |||||
} | |||||
header .header-content .header-content-inner p { | |||||
margin-right: auto; | |||||
margin-left: auto; | |||||
max-width: 80%; | |||||
font-size: 18px; | |||||
} | |||||
} | |||||
.section-heading { | |||||
margin-top: 0; | |||||
} | |||||
.service-box { | |||||
margin: 50px auto 0; | |||||
max-width: 400px; | |||||
} | |||||
@media(min-width:992px) { | |||||
.service-box { | |||||
margin: 20px auto 0; | |||||
} | |||||
} | |||||
.service-box p { | |||||
margin-bottom: 0; | |||||
} | |||||
.portfolio-box { | |||||
display: block; | |||||
position: relative; | |||||
margin: 0 auto; | |||||
max-width: 650px; | |||||
} | |||||
.portfolio-box .portfolio-box-caption { | |||||
display: block; | |||||
position: absolute; | |||||
bottom: 0; | |||||
width: 100%; | |||||
height: 100%; | |||||
text-align: center; | |||||
color: #fff; | |||||
opacity: 0; | |||||
background: rgba(240,95,64,.9); | |||||
-webkit-transition: all .35s; | |||||
-moz-transition: all .35s; | |||||
transition: all .35s; | |||||
} | |||||
.portfolio-box .portfolio-box-caption .portfolio-box-caption-content { | |||||
position: absolute; | |||||
top: 50%; | |||||
width: 100%; | |||||
text-align: center; | |||||
transform: translateY(-50%); | |||||
} | |||||
.portfolio-box .portfolio-box-caption .portfolio-box-caption-content .project-category, | |||||
.portfolio-box .portfolio-box-caption .portfolio-box-caption-content .project-name { | |||||
padding: 0 15px; | |||||
font-family: 'Open Sans','Helvetica Neue',Arial,sans-serif; | |||||
} | |||||
.portfolio-box .portfolio-box-caption .portfolio-box-caption-content .project-category { | |||||
text-transform: uppercase; | |||||
font-size: 14px; | |||||
font-weight: 600; | |||||
} | |||||
.portfolio-box .portfolio-box-caption .portfolio-box-caption-content .project-name { | |||||
font-size: 18px; | |||||
} | |||||
.portfolio-box:hover .portfolio-box-caption { | |||||
opacity: 1; | |||||
} | |||||
@media(min-width:768px) { | |||||
.portfolio-box .portfolio-box-caption .portfolio-box-caption-content .project-category { | |||||
font-size: 16px; | |||||
} | |||||
.portfolio-box .portfolio-box-caption .portfolio-box-caption-content .project-name { | |||||
font-size: 22px; | |||||
} | |||||
} | |||||
.call-to-action h2 { | |||||
margin: 0 auto 20px; | |||||
} | |||||
.text-primary { | |||||
color: #f05f40; | |||||
} | |||||
.no-gutter > [class*=col-] { | |||||
padding-right: 0; | |||||
padding-left: 0; | |||||
} | |||||
.btn-default { | |||||
border-color: #fff; | |||||
color: #222; | |||||
background-color: #fff; | |||||
-webkit-transition: all .35s; | |||||
-moz-transition: all .35s; | |||||
transition: all .35s; | |||||
} | |||||
.btn-default:hover, | |||||
.btn-default:focus, | |||||
.btn-default.focus, | |||||
.btn-default:active, | |||||
.btn-default.active, | |||||
.open > .dropdown-toggle.btn-default { | |||||
border-color: #ededed; | |||||
color: #222; | |||||
background-color: #f2f2f2; | |||||
} | |||||
.btn-default:active, | |||||
.btn-default.active, | |||||
.open > .dropdown-toggle.btn-default { | |||||
background-image: none; | |||||
} | |||||
.btn-default.disabled, | |||||
.btn-default[disabled], | |||||
fieldset[disabled] .btn-default, | |||||
.btn-default.disabled:hover, | |||||
.btn-default[disabled]:hover, | |||||
fieldset[disabled] .btn-default:hover, | |||||
.btn-default.disabled:focus, | |||||
.btn-default[disabled]:focus, | |||||
fieldset[disabled] .btn-default:focus, | |||||
.btn-default.disabled.focus, | |||||
.btn-default[disabled].focus, | |||||
fieldset[disabled] .btn-default.focus, | |||||
.btn-default.disabled:active, | |||||
.btn-default[disabled]:active, | |||||
fieldset[disabled] .btn-default:active, | |||||
.btn-default.disabled.active, | |||||
.btn-default[disabled].active, | |||||
fieldset[disabled] .btn-default.active { | |||||
border-color: #fff; | |||||
background-color: #fff; | |||||
} | |||||
.btn-default .badge { | |||||
color: #fff; | |||||
background-color: #222; | |||||
} | |||||
.btn-primary { | |||||
border-color: #f05f40; | |||||
color: #fff; | |||||
background-color: #f05f40; | |||||
-webkit-transition: all .35s; | |||||
-moz-transition: all .35s; | |||||
transition: all .35s; | |||||
} | |||||
.btn-primary:hover, | |||||
.btn-primary:focus, | |||||
.btn-primary.focus, | |||||
.btn-primary:active, | |||||
.btn-primary.active, | |||||
.open > .dropdown-toggle.btn-primary { | |||||
border-color: #ed431f; | |||||
color: #fff; | |||||
background-color: #ee4b28; | |||||
} | |||||
.btn-primary:active, | |||||
.btn-primary.active, | |||||
.open > .dropdown-toggle.btn-primary { | |||||
background-image: none; | |||||
} | |||||
.btn-primary.disabled, | |||||
.btn-primary[disabled], | |||||
fieldset[disabled] .btn-primary, | |||||
.btn-primary.disabled:hover, | |||||
.btn-primary[disabled]:hover, | |||||
fieldset[disabled] .btn-primary:hover, | |||||
.btn-primary.disabled:focus, | |||||
.btn-primary[disabled]:focus, | |||||
fieldset[disabled] .btn-primary:focus, | |||||
.btn-primary.disabled.focus, | |||||
.btn-primary[disabled].focus, | |||||
fieldset[disabled] .btn-primary.focus, | |||||
.btn-primary.disabled:active, | |||||
.btn-primary[disabled]:active, | |||||
fieldset[disabled] .btn-primary:active, | |||||
.btn-primary.disabled.active, | |||||
.btn-primary[disabled].active, | |||||
fieldset[disabled] .btn-primary.active { | |||||
border-color: #f05f40; | |||||
background-color: #f05f40; | |||||
} | |||||
.btn-primary .badge { | |||||
color: #f05f40; | |||||
background-color: #fff; | |||||
} | |||||
.btn { | |||||
border: 0; | |||||
border-radius: 300px; | |||||
text-transform: uppercase; | |||||
font-family: 'Open Sans','Helvetica Neue',Arial,sans-serif; | |||||
font-weight: 700; | |||||
} | |||||
.btn-xl { | |||||
padding: 15px 30px; | |||||
} | |||||
::-moz-selection { | |||||
text-shadow: none; | |||||
color: #fff; | |||||
background: #222; | |||||
} | |||||
::selection { | |||||
text-shadow: none; | |||||
color: #fff; | |||||
background: #222; | |||||
} | |||||
img::selection { | |||||
color: #fff; | |||||
background: 0 0; | |||||
} | |||||
img::-moz-selection { | |||||
color: #fff; | |||||
background: 0 0; | |||||
} | |||||
body { | |||||
webkit-tap-highlight-color: #222; | |||||
} |
@ -0,0 +1,22 @@ | |||||
{% extends "base.html" %} | |||||
{% load bootstrap3 %} | |||||
{% block content %} | |||||
<h1>Log In</h1> | |||||
<p> | |||||
Please enter your email address. | |||||
Next, we'll send you an email with log-in instructions! | |||||
</p> | |||||
<form method="post"> | |||||
{% csrf_token %} | |||||
{% bootstrap_form form %} | |||||
{% buttons %} | |||||
<button type="submit" class="btn btn-primary"> | |||||
Submit | |||||
</button> | |||||
{% endbuttons %} | |||||
</form> | |||||
{% endblock %} |
@ -0,0 +1,5 @@ | |||||
{% extends "base.html" %} | |||||
{% block content %} | |||||
<h1>Login link sent, check your inbox!</h1> | |||||
{% endblock %} |
@ -0,0 +1,15 @@ | |||||
<!DOCTYPE html> | |||||
<html lang="en"> | |||||
<head> | |||||
<meta charset="utf-8"> | |||||
<title>Waka Waka</title> | |||||
{% load staticfiles %} | |||||
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}" type="text/css"> | |||||
</head> | |||||
<body> | |||||
<div class="container"> | |||||
{% block content %}{% endblock %} | |||||
</div> | |||||
</body> | |||||
</html> |