Compare commits
12 Commits
6-simple-s
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
24cdebe960 | ||
|
1edd0892af | ||
|
d56b5725a0 | ||
|
3b05d0983a | ||
|
9d4ce6c413 | ||
|
d0d25ef499 | ||
|
832e39fcd7 | ||
|
1dd1188bdc | ||
|
cd2e4fca26 | ||
|
9930bec65a | ||
6ba83ac2d3 | |||
|
ebb48c1a42 |
1
.python-version
Normal file
@ -0,0 +1 @@
|
||||
3.9.0
|
20
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Python: Django",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/api/manage.py",
|
||||
"args": [
|
||||
"runserver",
|
||||
"0.0.0.0:9000"
|
||||
],
|
||||
"django": true,
|
||||
"justMyCode": true
|
||||
}
|
||||
]
|
||||
}
|
3
.vscode/settings.json
vendored
@ -16,7 +16,8 @@
|
||||
"titleBar.activeBackground": "#f9e64f",
|
||||
"titleBar.activeForeground": "#15202b",
|
||||
"titleBar.inactiveBackground": "#f9e64f99",
|
||||
"titleBar.inactiveForeground": "#15202b99"
|
||||
"titleBar.inactiveForeground": "#15202b99",
|
||||
"commandCenter.border": "#15202b99"
|
||||
},
|
||||
"peacock.color": "#f9e64f"
|
||||
}
|
28
README.md
@ -5,14 +5,36 @@ The AHosking.com API
|
||||
## Getting Started
|
||||
|
||||
###
|
||||
|
||||
1. `sudo apt install libpq-dev python-dev python3-psycopg2`
|
||||
1. `pip install virtualenv`
|
||||
1. `python3 -m virtualenv .env`
|
||||
1. Activate environment
|
||||
`.\.env\Scripts\activate`
|
||||
1.
|
||||
`.\.env\Scripts\activate`
|
||||
1. `export DEBUG=false`
|
||||
1. `docker run --name api-postgres -e POSTGRES_PASSWORD=mysecretpassword -e POSTGRES_USER=api -e POSTGRES_DB=api -p 5432:5432 -d postgres`
|
||||
1. ```
|
||||
export DATABASE_HOST=localhost
|
||||
export DATABASE_PORT=5432
|
||||
export DATABASE_USER=api
|
||||
export DATABASE_PASSWORD=mysecretpassword
|
||||
export DATABASE_NAME=api
|
||||
```
|
||||
1. `python3 manage.py makemigrations`
|
||||
1. `python3 manage.py migrate`
|
||||
1. `python3 manage.py createsuperuser`
|
||||
1. `python manage.py runserver 0.0.0.0:9000`
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
`pip3 install --upgrade --force-reinstall -r requirements.txt` will re-install requirements and upgrade based on requirements.txt
|
||||
|
||||
### Third-party
|
||||
|
||||
* https://pypi.org/project/django-3-jet/
|
||||
- https://pypi.org/project/django-4-jet/
|
||||
|
||||
## Themes and Templates
|
||||
|
||||
- https://startbootstrap.com/theme/landing-page
|
||||
- https://startbootstrap.com/previews/new-age
|
||||
- https://startbootstrap.com/theme/new-age
|
||||
|
0
api/accounts/__init__.py
Normal file
3
api/accounts/admin.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
6
api/accounts/apps.py
Normal file
@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class AccountsConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'accounts'
|
0
api/accounts/migrations/__init__.py
Normal file
3
api/accounts/models.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
3
api/accounts/tests.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
3
api/accounts/views.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
@ -4,6 +4,8 @@ from jet.dashboard.dashboard import Dashboard, AppIndexDashboard
|
||||
|
||||
|
||||
class CustomIndexDashboard(Dashboard):
|
||||
# app_label = "api"
|
||||
|
||||
columns = 3
|
||||
|
||||
def init_with_context(self, context):
|
||||
|
@ -12,6 +12,8 @@ https://docs.djangoproject.com/en/3.2/ref/settings/
|
||||
|
||||
from pathlib import Path
|
||||
import environ
|
||||
import os
|
||||
import environ
|
||||
|
||||
env = environ.Env()
|
||||
environ.Env.read_env()
|
||||
@ -24,20 +26,22 @@ BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = env("SECRET_KEY", default='django-insecure-7uajhmbt^@)mklk1ur=slkmn3*+9_cnfhww6wi8jg*h@qqd%6u')
|
||||
SECRET_KEY = env(
|
||||
"SECRET_KEY", default='django-insecure-7uajhmbt^@)mklk1ur=slkmn3*+9_cnfhww6wi8jg*h@qqd%6u')
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = env("DEBUG")
|
||||
|
||||
ALLOWED_HOSTS = ["127.0.0.1", "192.168.1.187", "192.168.1.23"]
|
||||
ALLOWED_HOSTS = ["localhost", "127.0.0.1", "192.168.1.187",
|
||||
"192.168.1.23", "192.168.1.125", "0.0.0.0"]
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'jet.dashboard',
|
||||
'jet',
|
||||
'bills.apps.BillsConfig',
|
||||
'bills',
|
||||
# 'bills.apps.BillsConfig',
|
||||
'admin_soft.apps.AdminSoftDashboardConfig',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
@ -47,6 +51,7 @@ INSTALLED_APPS = [
|
||||
'rest_framework',
|
||||
'rest_framework.authtoken',
|
||||
'django_filters',
|
||||
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
@ -64,7 +69,7 @@ ROOT_URLCONF = 'api.urls'
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [],
|
||||
'DIRS': [os.path.join(BASE_DIR, 'templates'), os.path.join(BASE_DIR, 'api/templates')],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
@ -129,7 +134,7 @@ USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/3.2/howto/static-files/
|
||||
# https://docs.djangoproject.com/en/4.2/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
@ -140,9 +145,9 @@ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||
|
||||
JET_THEMES = [
|
||||
{
|
||||
'theme': 'default', # theme folder name
|
||||
'color': '#47bac1', # color of the theme's button in user menu
|
||||
'title': 'Default' # theme title
|
||||
'theme': 'default', # theme folder name
|
||||
'color': '#47bac1', # color of the theme's button in user menu
|
||||
'title': 'Default' # theme title
|
||||
},
|
||||
{
|
||||
'theme': 'green',
|
||||
@ -172,5 +177,11 @@ JET_THEMES = [
|
||||
]
|
||||
|
||||
# JET_INDEX_DASHBOARD = 'jet.dashboard.dashboard.DefaultIndexDashboard'
|
||||
JET_APP_INDEX_DASHBOARD = 'dashboard.CustomIndexDashboard'
|
||||
# JET_INDEX_DASHBOARD = 'dashboard.CustomIndexDashboard'
|
||||
# JET_APP_INDEX_DASHBOARD = 'dashboard.CustomIndexDashboard'
|
||||
JET_INDEX_DASHBOARD = 'dashboard.CustomIndexDashboard'
|
||||
|
||||
|
||||
STATICFILES_DIRS = [
|
||||
BASE_DIR / "api/static",
|
||||
("assets", BASE_DIR / "api/static/assets"),
|
||||
]
|
||||
|
BIN
api/api/static/assets/favicon.ico
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
api/api/static/assets/img/bg-masthead.jpg
Normal file
After Width: | Height: | Size: 939 KiB |
BIN
api/api/static/assets/img/bg-showcase-1.jpg
Normal file
After Width: | Height: | Size: 298 KiB |
BIN
api/api/static/assets/img/bg-showcase-2.jpg
Normal file
After Width: | Height: | Size: 193 KiB |
BIN
api/api/static/assets/img/bg-showcase-3.jpg
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
api/api/static/assets/img/testimonials-1.jpg
Normal file
After Width: | Height: | Size: 133 KiB |
BIN
api/api/static/assets/img/testimonials-2.jpg
Normal file
After Width: | Height: | Size: 189 KiB |
BIN
api/api/static/assets/img/testimonials-3.jpg
Normal file
After Width: | Height: | Size: 244 KiB |
4124
api/api/static/css/bootstrap-grid.css
vendored
Normal file
1
api/api/static/css/bootstrap-grid.css.map
Normal file
7
api/api/static/css/bootstrap-grid.min.css
vendored
Normal file
1
api/api/static/css/bootstrap-grid.min.css.map
Normal file
4123
api/api/static/css/bootstrap-grid.rtl.css
vendored
Normal file
1
api/api/static/css/bootstrap-grid.rtl.css.map
Normal file
7
api/api/static/css/bootstrap-grid.rtl.min.css
vendored
Normal file
1
api/api/static/css/bootstrap-grid.rtl.min.css.map
Normal file
488
api/api/static/css/bootstrap-reboot.css
vendored
Normal file
@ -0,0 +1,488 @@
|
||||
/*!
|
||||
* Bootstrap Reboot v5.2.3 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2022 The Bootstrap Authors
|
||||
* Copyright 2011-2022 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
:root {
|
||||
--bs-blue: #0d6efd;
|
||||
--bs-indigo: #6610f2;
|
||||
--bs-purple: #6f42c1;
|
||||
--bs-pink: #d63384;
|
||||
--bs-red: #dc3545;
|
||||
--bs-orange: #fd7e14;
|
||||
--bs-yellow: #ffc107;
|
||||
--bs-green: #198754;
|
||||
--bs-teal: #20c997;
|
||||
--bs-cyan: #0dcaf0;
|
||||
--bs-black: #000;
|
||||
--bs-white: #fff;
|
||||
--bs-gray: #6c757d;
|
||||
--bs-gray-dark: #343a40;
|
||||
--bs-gray-100: #f8f9fa;
|
||||
--bs-gray-200: #e9ecef;
|
||||
--bs-gray-300: #dee2e6;
|
||||
--bs-gray-400: #ced4da;
|
||||
--bs-gray-500: #adb5bd;
|
||||
--bs-gray-600: #6c757d;
|
||||
--bs-gray-700: #495057;
|
||||
--bs-gray-800: #343a40;
|
||||
--bs-gray-900: #212529;
|
||||
--bs-primary: #0d6efd;
|
||||
--bs-secondary: #6c757d;
|
||||
--bs-success: #198754;
|
||||
--bs-info: #0dcaf0;
|
||||
--bs-warning: #ffc107;
|
||||
--bs-danger: #dc3545;
|
||||
--bs-light: #f8f9fa;
|
||||
--bs-dark: #212529;
|
||||
--bs-primary-rgb: 13, 110, 253;
|
||||
--bs-secondary-rgb: 108, 117, 125;
|
||||
--bs-success-rgb: 25, 135, 84;
|
||||
--bs-info-rgb: 13, 202, 240;
|
||||
--bs-warning-rgb: 255, 193, 7;
|
||||
--bs-danger-rgb: 220, 53, 69;
|
||||
--bs-light-rgb: 248, 249, 250;
|
||||
--bs-dark-rgb: 33, 37, 41;
|
||||
--bs-white-rgb: 255, 255, 255;
|
||||
--bs-black-rgb: 0, 0, 0;
|
||||
--bs-body-color-rgb: 33, 37, 41;
|
||||
--bs-body-bg-rgb: 255, 255, 255;
|
||||
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
|
||||
--bs-body-font-family: var(--bs-font-sans-serif);
|
||||
--bs-body-font-size: 1rem;
|
||||
--bs-body-font-weight: 400;
|
||||
--bs-body-line-height: 1.5;
|
||||
--bs-body-color: #212529;
|
||||
--bs-body-bg: #fff;
|
||||
--bs-border-width: 1px;
|
||||
--bs-border-style: solid;
|
||||
--bs-border-color: #dee2e6;
|
||||
--bs-border-color-translucent: rgba(0, 0, 0, 0.175);
|
||||
--bs-border-radius: 0.375rem;
|
||||
--bs-border-radius-sm: 0.25rem;
|
||||
--bs-border-radius-lg: 0.5rem;
|
||||
--bs-border-radius-xl: 1rem;
|
||||
--bs-border-radius-2xl: 2rem;
|
||||
--bs-border-radius-pill: 50rem;
|
||||
--bs-link-color: #0d6efd;
|
||||
--bs-link-hover-color: #0a58ca;
|
||||
--bs-code-color: #d63384;
|
||||
--bs-highlight-bg: #fff3cd;
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
:root {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: var(--bs-body-font-family);
|
||||
font-size: var(--bs-body-font-size);
|
||||
font-weight: var(--bs-body-font-weight);
|
||||
line-height: var(--bs-body-line-height);
|
||||
color: var(--bs-body-color);
|
||||
text-align: var(--bs-body-text-align);
|
||||
background-color: var(--bs-body-bg);
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 1rem 0;
|
||||
color: inherit;
|
||||
border: 0;
|
||||
border-top: 1px solid;
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
h6, h5, h4, h3, h2, h1 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: calc(1.375rem + 1.5vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: calc(1.325rem + 0.9vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: calc(1.3rem + 0.6vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h3 {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h4 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
abbr[title] {
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted;
|
||||
cursor: help;
|
||||
-webkit-text-decoration-skip-ink: none;
|
||||
text-decoration-skip-ink: none;
|
||||
}
|
||||
|
||||
address {
|
||||
margin-bottom: 1rem;
|
||||
font-style: normal;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-bottom: 0.5rem;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
mark {
|
||||
padding: 0.1875em;
|
||||
background-color: var(--bs-highlight-bg);
|
||||
}
|
||||
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 0.75em;
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--bs-link-color);
|
||||
text-decoration: underline;
|
||||
}
|
||||
a:hover {
|
||||
color: var(--bs-link-hover-color);
|
||||
}
|
||||
|
||||
a:not([href]):not([class]), a:not([href]):not([class]):hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: var(--bs-font-monospace);
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
overflow: auto;
|
||||
font-size: 0.875em;
|
||||
}
|
||||
pre code {
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 0.875em;
|
||||
color: var(--bs-code-color);
|
||||
word-wrap: break-word;
|
||||
}
|
||||
a > code {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
kbd {
|
||||
padding: 0.1875rem 0.375rem;
|
||||
font-size: 0.875em;
|
||||
color: var(--bs-body-bg);
|
||||
background-color: var(--bs-body-color);
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
kbd kbd {
|
||||
padding: 0;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
img,
|
||||
svg {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
table {
|
||||
caption-side: bottom;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
caption {
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
color: #6c757d;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: inherit;
|
||||
text-align: -webkit-match-parent;
|
||||
}
|
||||
|
||||
thead,
|
||||
tbody,
|
||||
tfoot,
|
||||
tr,
|
||||
td,
|
||||
th {
|
||||
border-color: inherit;
|
||||
border-style: solid;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button:focus:not(:focus-visible) {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
optgroup,
|
||||
textarea {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
[role=button] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
select {
|
||||
word-wrap: normal;
|
||||
}
|
||||
select:disabled {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
button,
|
||||
[type=button],
|
||||
[type=reset],
|
||||
[type=submit] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
button:not(:disabled),
|
||||
[type=button]:not(:disabled),
|
||||
[type=reset]:not(:disabled),
|
||||
[type=submit]:not(:disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
float: left;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
line-height: inherit;
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
legend {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
legend + * {
|
||||
clear: left;
|
||||
}
|
||||
|
||||
::-webkit-datetime-edit-fields-wrapper,
|
||||
::-webkit-datetime-edit-text,
|
||||
::-webkit-datetime-edit-minute,
|
||||
::-webkit-datetime-edit-hour-field,
|
||||
::-webkit-datetime-edit-day-field,
|
||||
::-webkit-datetime-edit-month-field,
|
||||
::-webkit-datetime-edit-year-field {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-inner-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
[type=search] {
|
||||
outline-offset: -2px;
|
||||
-webkit-appearance: textfield;
|
||||
}
|
||||
|
||||
/* rtl:raw:
|
||||
[type="tel"],
|
||||
[type="url"],
|
||||
[type="email"],
|
||||
[type="number"] {
|
||||
direction: ltr;
|
||||
}
|
||||
*/
|
||||
::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
::-webkit-color-swatch-wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
::file-selector-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
output {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
iframe {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/*# sourceMappingURL=bootstrap-reboot.css.map */
|
1
api/api/static/css/bootstrap-reboot.css.map
Normal file
7
api/api/static/css/bootstrap-reboot.min.css
vendored
Normal file
1
api/api/static/css/bootstrap-reboot.min.css.map
Normal file
485
api/api/static/css/bootstrap-reboot.rtl.css
vendored
Normal file
@ -0,0 +1,485 @@
|
||||
/*!
|
||||
* Bootstrap Reboot v5.2.3 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2022 The Bootstrap Authors
|
||||
* Copyright 2011-2022 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
:root {
|
||||
--bs-blue: #0d6efd;
|
||||
--bs-indigo: #6610f2;
|
||||
--bs-purple: #6f42c1;
|
||||
--bs-pink: #d63384;
|
||||
--bs-red: #dc3545;
|
||||
--bs-orange: #fd7e14;
|
||||
--bs-yellow: #ffc107;
|
||||
--bs-green: #198754;
|
||||
--bs-teal: #20c997;
|
||||
--bs-cyan: #0dcaf0;
|
||||
--bs-black: #000;
|
||||
--bs-white: #fff;
|
||||
--bs-gray: #6c757d;
|
||||
--bs-gray-dark: #343a40;
|
||||
--bs-gray-100: #f8f9fa;
|
||||
--bs-gray-200: #e9ecef;
|
||||
--bs-gray-300: #dee2e6;
|
||||
--bs-gray-400: #ced4da;
|
||||
--bs-gray-500: #adb5bd;
|
||||
--bs-gray-600: #6c757d;
|
||||
--bs-gray-700: #495057;
|
||||
--bs-gray-800: #343a40;
|
||||
--bs-gray-900: #212529;
|
||||
--bs-primary: #0d6efd;
|
||||
--bs-secondary: #6c757d;
|
||||
--bs-success: #198754;
|
||||
--bs-info: #0dcaf0;
|
||||
--bs-warning: #ffc107;
|
||||
--bs-danger: #dc3545;
|
||||
--bs-light: #f8f9fa;
|
||||
--bs-dark: #212529;
|
||||
--bs-primary-rgb: 13, 110, 253;
|
||||
--bs-secondary-rgb: 108, 117, 125;
|
||||
--bs-success-rgb: 25, 135, 84;
|
||||
--bs-info-rgb: 13, 202, 240;
|
||||
--bs-warning-rgb: 255, 193, 7;
|
||||
--bs-danger-rgb: 220, 53, 69;
|
||||
--bs-light-rgb: 248, 249, 250;
|
||||
--bs-dark-rgb: 33, 37, 41;
|
||||
--bs-white-rgb: 255, 255, 255;
|
||||
--bs-black-rgb: 0, 0, 0;
|
||||
--bs-body-color-rgb: 33, 37, 41;
|
||||
--bs-body-bg-rgb: 255, 255, 255;
|
||||
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
|
||||
--bs-body-font-family: var(--bs-font-sans-serif);
|
||||
--bs-body-font-size: 1rem;
|
||||
--bs-body-font-weight: 400;
|
||||
--bs-body-line-height: 1.5;
|
||||
--bs-body-color: #212529;
|
||||
--bs-body-bg: #fff;
|
||||
--bs-border-width: 1px;
|
||||
--bs-border-style: solid;
|
||||
--bs-border-color: #dee2e6;
|
||||
--bs-border-color-translucent: rgba(0, 0, 0, 0.175);
|
||||
--bs-border-radius: 0.375rem;
|
||||
--bs-border-radius-sm: 0.25rem;
|
||||
--bs-border-radius-lg: 0.5rem;
|
||||
--bs-border-radius-xl: 1rem;
|
||||
--bs-border-radius-2xl: 2rem;
|
||||
--bs-border-radius-pill: 50rem;
|
||||
--bs-link-color: #0d6efd;
|
||||
--bs-link-hover-color: #0a58ca;
|
||||
--bs-code-color: #d63384;
|
||||
--bs-highlight-bg: #fff3cd;
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
:root {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: var(--bs-body-font-family);
|
||||
font-size: var(--bs-body-font-size);
|
||||
font-weight: var(--bs-body-font-weight);
|
||||
line-height: var(--bs-body-line-height);
|
||||
color: var(--bs-body-color);
|
||||
text-align: var(--bs-body-text-align);
|
||||
background-color: var(--bs-body-bg);
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 1rem 0;
|
||||
color: inherit;
|
||||
border: 0;
|
||||
border-top: 1px solid;
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
h6, h5, h4, h3, h2, h1 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: calc(1.375rem + 1.5vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: calc(1.325rem + 0.9vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: calc(1.3rem + 0.6vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h3 {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h4 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
abbr[title] {
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted;
|
||||
cursor: help;
|
||||
-webkit-text-decoration-skip-ink: none;
|
||||
text-decoration-skip-ink: none;
|
||||
}
|
||||
|
||||
address {
|
||||
margin-bottom: 1rem;
|
||||
font-style: normal;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
padding-right: 2rem;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-bottom: 0.5rem;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
mark {
|
||||
padding: 0.1875em;
|
||||
background-color: var(--bs-highlight-bg);
|
||||
}
|
||||
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 0.75em;
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--bs-link-color);
|
||||
text-decoration: underline;
|
||||
}
|
||||
a:hover {
|
||||
color: var(--bs-link-hover-color);
|
||||
}
|
||||
|
||||
a:not([href]):not([class]), a:not([href]):not([class]):hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: var(--bs-font-monospace);
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
overflow: auto;
|
||||
font-size: 0.875em;
|
||||
}
|
||||
pre code {
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 0.875em;
|
||||
color: var(--bs-code-color);
|
||||
word-wrap: break-word;
|
||||
}
|
||||
a > code {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
kbd {
|
||||
padding: 0.1875rem 0.375rem;
|
||||
font-size: 0.875em;
|
||||
color: var(--bs-body-bg);
|
||||
background-color: var(--bs-body-color);
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
kbd kbd {
|
||||
padding: 0;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
img,
|
||||
svg {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
table {
|
||||
caption-side: bottom;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
caption {
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
color: #6c757d;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: inherit;
|
||||
text-align: -webkit-match-parent;
|
||||
}
|
||||
|
||||
thead,
|
||||
tbody,
|
||||
tfoot,
|
||||
tr,
|
||||
td,
|
||||
th {
|
||||
border-color: inherit;
|
||||
border-style: solid;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button:focus:not(:focus-visible) {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
optgroup,
|
||||
textarea {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
[role=button] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
select {
|
||||
word-wrap: normal;
|
||||
}
|
||||
select:disabled {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
button,
|
||||
[type=button],
|
||||
[type=reset],
|
||||
[type=submit] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
button:not(:disabled),
|
||||
[type=button]:not(:disabled),
|
||||
[type=reset]:not(:disabled),
|
||||
[type=submit]:not(:disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
float: right;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
line-height: inherit;
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
legend {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
legend + * {
|
||||
clear: right;
|
||||
}
|
||||
|
||||
::-webkit-datetime-edit-fields-wrapper,
|
||||
::-webkit-datetime-edit-text,
|
||||
::-webkit-datetime-edit-minute,
|
||||
::-webkit-datetime-edit-hour-field,
|
||||
::-webkit-datetime-edit-day-field,
|
||||
::-webkit-datetime-edit-month-field,
|
||||
::-webkit-datetime-edit-year-field {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-inner-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
[type=search] {
|
||||
outline-offset: -2px;
|
||||
-webkit-appearance: textfield;
|
||||
}
|
||||
|
||||
[type="tel"],
|
||||
[type="url"],
|
||||
[type="email"],
|
||||
[type="number"] {
|
||||
direction: ltr;
|
||||
}
|
||||
::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
::-webkit-color-swatch-wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
::file-selector-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
output {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
iframe {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
/*# sourceMappingURL=bootstrap-reboot.rtl.css.map */
|
1
api/api/static/css/bootstrap-reboot.rtl.css.map
Normal file
7
api/api/static/css/bootstrap-reboot.rtl.min.css
vendored
Normal file
1
api/api/static/css/bootstrap-reboot.rtl.min.css.map
Normal file
4266
api/api/static/css/bootstrap-utilities.css
vendored
Normal file
1
api/api/static/css/bootstrap-utilities.css.map
Normal file
7
api/api/static/css/bootstrap-utilities.min.css
vendored
Normal file
1
api/api/static/css/bootstrap-utilities.min.css.map
Normal file
4257
api/api/static/css/bootstrap-utilities.rtl.css
vendored
Normal file
1
api/api/static/css/bootstrap-utilities.rtl.css.map
Normal file
7
api/api/static/css/bootstrap-utilities.rtl.min.css
vendored
Normal file
1
api/api/static/css/bootstrap-utilities.rtl.min.css.map
Normal file
10878
api/api/static/css/bootstrap.css
vendored
Normal file
1
api/api/static/css/bootstrap.css.map
Normal file
7
api/api/static/css/bootstrap.min.css
vendored
Normal file
1
api/api/static/css/bootstrap.min.css.map
Normal file
10842
api/api/static/css/bootstrap.rtl.css
vendored
Normal file
1
api/api/static/css/bootstrap.rtl.css.map
Normal file
7
api/api/static/css/bootstrap.rtl.min.css
vendored
Normal file
1
api/api/static/css/bootstrap.rtl.min.css.map
Normal file
10919
api/api/static/css/styles.css
Normal file
7075
api/api/static/js/bootstrap.bundle.js
vendored
Normal file
1
api/api/static/js/bootstrap.bundle.js.map
Normal file
7
api/api/static/js/bootstrap.bundle.min.js
vendored
Normal file
1
api/api/static/js/bootstrap.bundle.min.js.map
Normal file
5202
api/api/static/js/bootstrap.esm.js
vendored
Normal file
1
api/api/static/js/bootstrap.esm.js.map
Normal file
7
api/api/static/js/bootstrap.esm.min.js
vendored
Normal file
1
api/api/static/js/bootstrap.esm.min.js.map
Normal file
5249
api/api/static/js/bootstrap.js
vendored
Normal file
1
api/api/static/js/bootstrap.js.map
Normal file
7
api/api/static/js/bootstrap.min.js
vendored
Normal file
1
api/api/static/js/bootstrap.min.js.map
Normal file
7
api/api/static/js/scripts.js
Normal file
@ -0,0 +1,7 @@
|
||||
/*!
|
||||
* Start Bootstrap - Landing Page v6.0.6 (https://startbootstrap.com/theme/landing-page)
|
||||
* Copyright 2013-2023 Start Bootstrap
|
||||
* Licensed under MIT (https://github.com/StartBootstrap/startbootstrap-landing-page/blob/master/LICENSE)
|
||||
*/
|
||||
// This file is intentionally blank
|
||||
// Use this file to add JavaScript to your project
|
14
api/api/templates/bills/index.html
Normal file
@ -0,0 +1,14 @@
|
||||
<b>Bills!</b>
|
||||
<ul>
|
||||
<li><a href="{% url 'bills:create' %}">Create Bill</a></li>
|
||||
</ul>
|
||||
<hr>
|
||||
{% if bills_list %}
|
||||
<ul>
|
||||
{% for bill in bills_list %}
|
||||
<li><a href="{% url 'bills:detail' bill.id %}"> {{ bill.name }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p>No bills are available.</p>
|
||||
{% endif %}
|
100
api/api/templates/index.html
Normal file
@ -0,0 +1,100 @@
|
||||
{% load static %}
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Bootstrap demo</title>
|
||||
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<header class="p-3 text-bg-dark">
|
||||
<div class="container">
|
||||
<div class="d-flex flex-wrap align-items-center justify-content-center justify-content-lg-start">
|
||||
<a href="/" class="d-flex align-items-center mb-2 mb-lg-0 text-white text-decoration-none">
|
||||
<svg class="bi me-2" width="40" height="32" role="img" aria-label="Bootstrap"><use xlink:href="#bootstrap"></use></svg>
|
||||
</a>
|
||||
|
||||
<ul class="nav col-12 col-lg-auto me-lg-auto mb-2 justify-content-center mb-md-0">
|
||||
<li><a href="#" class="nav-link px-2 text-secondary">Home</a></li>
|
||||
<li><a href="#" class="nav-link px-2 text-white">Features</a></li>
|
||||
<li><a href="#" class="nav-link px-2 text-white">Pricing</a></li>
|
||||
<li><a href="#" class="nav-link px-2 text-white">FAQs</a></li>
|
||||
<li><a href="#" class="nav-link px-2 text-white">About</a></li>
|
||||
</ul>
|
||||
|
||||
<form class="col-12 col-lg-auto mb-3 mb-lg-0 me-lg-3" role="search">
|
||||
<input type="search" class="form-control form-control-dark text-bg-dark" placeholder="Search..." aria-label="Search">
|
||||
</form>
|
||||
|
||||
<div class="text-end">
|
||||
<button type="button" class="btn btn-outline-light me-2">Login</button>
|
||||
<button type="button" class="btn btn-warning">Sign-up</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<script src="{% static 'js/bootstrap.bundle.min.js' %}" crossorigin="anonymous"></script>
|
||||
<!-- end header -->
|
||||
<div class="col-lg-8 mx-auto p-4 py-md-5">
|
||||
<!-- main -->
|
||||
<main>
|
||||
<h1>Bills</h1>
|
||||
<p class="fs-5 col-md-8">Quickly and easily start adding your bills and service costs to get a better understanding of your operational expenses.</p>
|
||||
|
||||
<div class="mb-5">
|
||||
<a href="#" class="btn btn-primary btn-lg px-4">Sign-up!</a>
|
||||
</div>
|
||||
|
||||
<hr class="col-3 col-md-2 mb-5">
|
||||
|
||||
<div class="row g-5">
|
||||
<div class="col-md-6">
|
||||
<h2>Starter projects</h2>
|
||||
<p>Ready to beyond the starter template? Check out these open source projects that you can quickly duplicate to a new GitHub repository.</p>
|
||||
<ul class="icon-list ps-0">
|
||||
<li class="d-flex align-items-start mb-1"><a href="https://github.com/twbs/bootstrap-npm-starter" rel="noopener" target="_blank">Bootstrap npm starter</a></li>
|
||||
<li class="text-muted d-flex align-items-start mb-1">Bootstrap Parcel starter (coming soon!)</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<h2>Guides</h2>
|
||||
<p>Read more detailed instructions and documentation on using or contributing to Bootstrap.</p>
|
||||
<ul class="icon-list ps-0">
|
||||
<li class="d-flex align-items-start mb-1"><a href="../getting-started/introduction/">Bootstrap quick start guide</a></li>
|
||||
<li class="d-flex align-items-start mb-1"><a href="../getting-started/webpack/">Bootstrap Webpack guide</a></li>
|
||||
<li class="d-flex align-items-start mb-1"><a href="../getting-started/parcel/">Bootstrap Parcel guide</a></li>
|
||||
<li class="d-flex align-items-start mb-1"><a href="../getting-started/vite/">Bootstrap Vite guide</a></li>
|
||||
<li class="d-flex align-items-start mb-1"><a href="../getting-started/contribute/">Contributing to Bootstrap</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<!-- end main -->
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- footer -->
|
||||
<div class="container">
|
||||
<footer class="d-flex flex-wrap justify-content-between align-items-center py-3 my-4 border-top">
|
||||
<p class="col-md-4 mb-0 text-muted">© 2022 Automated Bytes Inc.</p>
|
||||
|
||||
<a href="/" class="col-md-4 d-flex align-items-center justify-content-center mb-3 mb-md-0 me-md-auto link-dark text-decoration-none">
|
||||
<svg class="bi me-2" width="40" height="32"><use xlink:href="#bootstrap"></use></svg>
|
||||
</a>
|
||||
|
||||
<ul class="nav col-md-4 justify-content-end">
|
||||
<li class="nav-item"><a href="#" class="nav-link px-2 text-muted">Home</a></li>
|
||||
<li class="nav-item"><a href="#" class="nav-link px-2 text-muted">Features</a></li>
|
||||
<li class="nav-item"><a href="#" class="nav-link px-2 text-muted">Pricing</a></li>
|
||||
<li class="nav-item"><a href="#" class="nav-link px-2 text-muted">FAQs</a></li>
|
||||
<li class="nav-item"><a href="#" class="nav-link px-2 text-muted">About</a></li>
|
||||
</ul>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@ -13,7 +13,7 @@ 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.conf.urls import url
|
||||
from django.urls import path
|
||||
from django.contrib import admin
|
||||
from django.views.generic import TemplateView
|
||||
from django.urls import include, path
|
||||
@ -24,10 +24,6 @@ urlpatterns = [
|
||||
# url(r'^$', view=TemplateView.as_view(template_name='bills/home.html')),
|
||||
# url(r'^$', view=TemplateView.as_view(template_name='main_api/home.html')),
|
||||
path('', views.index, name='index'),
|
||||
# url(r'^jet/', include('jet.urls', 'jet')), # Django JET URLS
|
||||
# url(r'^jet/dashboard/', include('jet.dashboard.urls', 'jet-dashboard')),
|
||||
path('jet/', include('jet.urls', 'jet')),
|
||||
path('jet/dashboard', include('jet.dashboard.urls', 'jet-dashboard')),
|
||||
path('bills/', include('bills.urls')),
|
||||
path('admin/', admin.site.urls),
|
||||
]
|
||||
|
@ -1,4 +1,16 @@
|
||||
from django.contrib.auth import logout
|
||||
from django.http import HttpResponse
|
||||
from django.template import loader
|
||||
from django.shortcuts import redirect
|
||||
|
||||
|
||||
def index(request):
|
||||
return HttpResponse("Hi there! This is the API index")
|
||||
# return HttpResponse("Hi there! This is the API index")
|
||||
template = loader.get_template('index.html')
|
||||
context = {}
|
||||
return HttpResponse(template.render(context, request))
|
||||
|
||||
|
||||
def logout(request):
|
||||
logout(request)
|
||||
redirect(index)
|
||||
|
@ -1,9 +1,21 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from .models import Bill
|
||||
from .models import Bill, Organization
|
||||
|
||||
|
||||
@admin.register(Bill)
|
||||
class BillAdmin(admin.ModelAdmin):
|
||||
list_display = ['name', 'due', 'amount']
|
||||
list_filter = ('name', 'type', 'is_paid', 'is_overdue', 'is_missed')
|
||||
search_fields = ['name', 'type', 'amount']
|
||||
search_fields = ['name', 'type', 'amount']
|
||||
|
||||
|
||||
@admin.register(Organization)
|
||||
class Organization(admin.ModelAdmin):
|
||||
list_display = ['name']
|
||||
search_fields = ['name']
|
||||
list_filter = ('name',)
|
||||
ordering = ['name']
|
||||
# prepopulated_fields = {'slug': ('name',)}
|
||||
# raw_id_fields = ('members',)
|
||||
# readonly_fields = ('members',)
|
||||
|
24
api/bills/migrations/0005_organization.py
Normal file
@ -0,0 +1,24 @@
|
||||
# Generated by Django 4.1.7 on 2023-04-08 15:19
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('bills', '0004_auto_20211203_1549'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Organization',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=64, verbose_name='Name')),
|
||||
('address', models.CharField(max_length=64, verbose_name='Address')),
|
||||
('phone', models.CharField(max_length=64, verbose_name='Phone')),
|
||||
('email', models.CharField(max_length=64, verbose_name='Email')),
|
||||
('website', models.CharField(max_length=64, verbose_name='Website')),
|
||||
],
|
||||
),
|
||||
]
|
19
api/bills/migrations/0006_bill_organization.py
Normal file
@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.1.7 on 2023-04-08 15:51
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('bills', '0005_organization'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='bill',
|
||||
name='organization',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='bills.organization', verbose_name='Organization'),
|
||||
),
|
||||
]
|
@ -1,18 +1,36 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
|
||||
|
||||
class Bill(models.Model):
|
||||
name = models.CharField(max_length=64, verbose_name='Name')
|
||||
type = models.CharField(max_length=64, verbose_name="Type")
|
||||
due = models.DateField(verbose_name="Due Date")
|
||||
amount = models.FloatField(default='00.00')
|
||||
is_paid = models.BooleanField(default=False, verbose_name="Paid")
|
||||
paid_date = models.DateField('Paid Date',null=True, blank=True)
|
||||
paid_date = models.DateField('Paid Date', null=True, blank=True)
|
||||
is_overdue = models.BooleanField(default=False, verbose_name="Overdue")
|
||||
is_missed = models.BooleanField(default=False, verbose_name='Missed Payment')
|
||||
is_missed = models.BooleanField(
|
||||
default=False, verbose_name='Missed Payment')
|
||||
organization = models.ForeignKey(
|
||||
'Organization', on_delete=models.CASCADE, verbose_name='Organization', null=True, blank=True)
|
||||
|
||||
def overdue(self):
|
||||
return self.is_overdue
|
||||
|
||||
def __str__(self):
|
||||
return ("%s - %s" % (self.name, self.due))
|
||||
|
||||
# Create organization model
|
||||
|
||||
|
||||
class Organization(models.Model):
|
||||
name = models.CharField(max_length=64, verbose_name='Name')
|
||||
address = models.CharField(max_length=64, verbose_name='Address')
|
||||
phone = models.CharField(max_length=64, verbose_name='Phone')
|
||||
email = models.CharField(max_length=64, verbose_name='Email')
|
||||
website = models.CharField(max_length=64, verbose_name='Website')
|
||||
|
||||
def __str__(self):
|
||||
return ("%s - %s" % (self.name, self.phone))
|
||||
|
10
api/bills/templates/bills/create.html
Normal file
@ -0,0 +1,10 @@
|
||||
<form action="{% url 'bills:create' %}" method="post">
|
||||
{% csrf_token %}
|
||||
<fieldset>
|
||||
<legend><h1>Create a New Bill</h1></legend>
|
||||
<label for="name">Bill Name:</label>
|
||||
<input type="text" name="name" id="name" value="">
|
||||
<br>
|
||||
</fieldset>
|
||||
<input type="submit" value="Create Bill">
|
||||
</form>
|
17
api/bills/templates/bills/detail.html
Normal file
@ -0,0 +1,17 @@
|
||||
<h1> {{bill.name }}</h1>
|
||||
|
||||
{{ bill.due}}
|
||||
<br>
|
||||
{{ bill.type }}
|
||||
<br>
|
||||
{{ bill.amount}}
|
||||
<br>
|
||||
{{ bill.is_paid}}
|
||||
<br>
|
||||
{{ bill.paid_date}}
|
||||
<br>
|
||||
{{ bill.is_overdue}}
|
||||
<br>
|
||||
{{ bill.is_missed}}
|
||||
<br>
|
||||
{{ bill.organization.name}}
|
14
api/bills/templates/bills/index.html
Normal file
@ -0,0 +1,14 @@
|
||||
<b>Bills!</b>
|
||||
<ul>
|
||||
<li><a href="{% url 'bills:create' %}">Create Bill</a></li>
|
||||
</ul>
|
||||
<hr>
|
||||
{% if bills_list %}
|
||||
<ul>
|
||||
{% for bill in bills_list %}
|
||||
<li><a href="{% url 'bills:detail' bill.id %}"> {{ bill.name }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p>No bills are available.</p>
|
||||
{% endif %}
|
@ -1,3 +1,9 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
from .models import Bill, Organization
|
||||
|
||||
|
||||
class BillModelTests(TestCase):
|
||||
def test_has_due_date_no_amount(self):
|
||||
pass
|
||||
|
@ -1,12 +1,15 @@
|
||||
from django.conf.urls import url
|
||||
from django.urls import path
|
||||
from django.contrib import admin
|
||||
from django.views.generic import TemplateView
|
||||
from django.urls import include, path
|
||||
|
||||
from . import views
|
||||
|
||||
app_name = 'bills'
|
||||
urlpatterns = [
|
||||
|
||||
path('', views.index, name='index'),
|
||||
path('admin/', admin.site.urls),
|
||||
path('<int:bill_id>/', views.detail, name='detail'),
|
||||
path('create', views.create, name='create')
|
||||
# path('admin/', admin.site.urls),
|
||||
]
|
||||
|
@ -1,6 +1,32 @@
|
||||
from django.shortcuts import render
|
||||
from django.http import HttpResponse
|
||||
# from django.shortcuts import render
|
||||
from django.contrib.auth import authenticate, login
|
||||
from django.http import HttpResponse, Http404
|
||||
from django.template import loader
|
||||
from django.shortcuts import render, get_object_or_404, get_list_or_404, redirect
|
||||
|
||||
from .models import Bill
|
||||
|
||||
|
||||
def index(request):
|
||||
return HttpResponse("Let there be bills!")
|
||||
# Create your views here.
|
||||
if request.user.is_authenticated:
|
||||
bills_list = Bill.objects.order_by('-due')
|
||||
# bills_list = get_list_or_404(Bill)
|
||||
template = loader.get_template('bills/index.html')
|
||||
context = {'bills_list': bills_list, }
|
||||
print(bills_list)
|
||||
return HttpResponse(template.render(context, request))
|
||||
else:
|
||||
# return redirect(api.index)
|
||||
return render(request, "index.html")
|
||||
# return render(request, 'bills/index.html', context)
|
||||
|
||||
|
||||
def detail(request, bill_id):
|
||||
bill = get_object_or_404(Bill, pk=bill_id)
|
||||
return render(request, 'bills/detail.html', {'bill': bill})
|
||||
|
||||
# view to retriev a users bills
|
||||
|
||||
|
||||
def create(request):
|
||||
return render(request, 'bills/create.html')
|
||||
|