added user system

This commit is contained in:
Jens Timmerman 2021-07-04 21:05:00 +02:00
parent 504ab9729d
commit af28efa2d4
27 changed files with 402 additions and 11 deletions

View File

@ -25,14 +25,19 @@ SECRET_KEY = '-h%7n38#ij*7$pzkv=8-+9axa6o6fk9e4z3x676774f&06-di9'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
ALLOWED_HOSTS = [
'0.0.0.0',
]
LOGIN_REDIRECT_URL = "im:index"
LOGOUT_REDIRECT_URL = "im:index"
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'users.apps.UsersConfig',
'django.contrib.auth',
'django.contrib.admin',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
@ -124,3 +129,7 @@ USE_TZ = True
# https://docs.djangoproject.com/en/2.1/howto/static-files/
STATIC_URL = '/static/'
EMAIL_HOST = 'mail.caret.be'
EMAIL_PORT = '25'

View File

@ -16,7 +16,11 @@ Including another URLconf
from django.contrib import admin
from django.urls import include, path
from users.views import register
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include('django.contrib.auth.urls')),
path("register/", register, name="register"),
path('', include('inventory.urls')),
]

View File

@ -29,7 +29,7 @@ upper_case_name.short_description = 'Name'
class PantryItemLineAdmin(admin.ModelAdmin):
list_filter = ['expiry_date', 'pantry_item__unit', 'pantry_item', 'pantry_item__min_quantity']
list_filter = ['expiry_date', 'pantry_item__unit', 'pantry_item', 'pantry_item__min_quantity', 'location']
search_fields = ['info', 'pantry_item__name', 'pantry_item__info']
autocomplete_fields = ['pantry_item']
@ -62,7 +62,7 @@ class LocationAdmin(AutocompleteAdmin):
class PantryItemAdmin(admin.ModelAdmin):
list_filter = ['category', 'unit', 'min_quantity', 'location']
list_filter = ['category', 'unit', 'min_quantity']
search_fields = ['info', 'name', 'category__name', 'unit__name']
autocomplete_fields = ['category', 'unit']
inlines = [PantryItemInLine]

View File

@ -0,0 +1,23 @@
# Generated by Django 3.2.4 on 2021-07-04 18:10
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('inventory', '0001_initial'),
]
operations = [
migrations.RemoveField(
model_name='pantryitem',
name='location',
),
migrations.AddField(
model_name='pantryitemline',
name='location',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='inventory.location'),
),
]

View File

@ -39,7 +39,7 @@ class Unit(models.Model):
class Location(models.Model):
"""Location for a pantry item line"""
name = models.CharField(max_length=200, null=True, blank=True)
name = models.CharField(max_length=200)
in_location = models.ForeignKey("self", on_delete=models.PROTECT, null=True, blank=True)
def __str__(self):
@ -47,6 +47,9 @@ class Location(models.Model):
return self.name + ' ' + str(self.in_location)
return self.name
class Meta:
unique_together = ('name', 'in_location')
class PantryItem(models.Model):
"""A think you keep in your pantry """
@ -60,9 +63,6 @@ class PantryItem(models.Model):
name = models.CharField(max_length=200)
unit = models.ForeignKey(Unit, on_delete=models.PROTECT, null=True)
info = models.CharField(max_length=200, null=True, blank=True)
# location is saved on a per item base, not itemline
# you can have multiple pantries with subpantries
location = models.ForeignKey(Location, on_delete=models.PROTECT, null=True, blank=True)
def __str__(self):
return self.name
@ -81,6 +81,8 @@ class PantryItemLine(models.Model):
size = models.IntegerField(default=1)
info = models.CharField(max_length=200, null=True, blank=True)
location = models.ForeignKey(Location, on_delete=models.PROTECT, null=True, blank=True)
def unit(self):
return self.pantry_item.unit

View File

@ -0,0 +1,89 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<title>Inventory Management</title>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="/">Inventory Management</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="{% url 'im:consumelist' %} ">Consume</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'im:additemline' %} ">Add</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'im:shoppinglist' %} ">Shopping List</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'im:expirations' %} ">Expirations</a>
</li>
<li class="nav-item">
{% if user.is_authenticated %}
<a class="nav-link" href="{% url 'logout' %}">Logout {{ user.username }}</a>
<li class="nav-item">
<a class="nav-link" href="{% url 'password_change' %} ">Change Password</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'admin:index' %} ">Admin</a>
</li>
{% else %}
<a class="nav-link" href="{% url 'login' %}">Login</a>
{% endif %}
</li>
<!--li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Dropdown
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link disabled" href="#">Disabled</a>
</li!-->
</ul>
<form class="form-inline my-2 my-lg-0" action="{% url 'admin:inventory_pantryitem_changelist' %}" method="GET">
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search" name="q">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
</nav>
<div class="container">
<div class="row justify-content-center">
<div class="col-8">
{% block content %}
BASE TEMPLATE
{% endblock %}
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
crossorigin="anonymous"></script>
</body>
</html>

View File

@ -21,7 +21,7 @@
<a class="nav-link" href="{% url 'im:consumelist' %} ">Consume</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'admin:inventory_pantryitem_changelist' %} ">Add</a>
<a class="nav-link" href="{% url 'im:additemline' %} ">Add</a>
</li>
<li class="nav-item">
@ -31,8 +31,22 @@
<a class="nav-link" href="{% url 'im:expirations' %} ">Expirations</a>
</li>
<li class="nav-item">
{% if user.is_authenticated %}
<a class="nav-link" href="{% url 'logout' %}">Logout {{ user.username }}</a>
<li class="nav-item">
<a class="nav-link" href="{% url 'password_change' %} ">Change Password</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'admin:index' %} ">Admin</a>
</li>
</li>
{% else %}
<a class="nav-link" href="{% url 'login' %}">Login</a>
{% endif %}
</li>
<!--li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">

View File

@ -0,0 +1,12 @@
{% extends 'inventory/base.html' %}
{% block content %}
<h2>Add Category</h2>
<form action="." method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit">
</form>
{% endblock %}

View File

@ -17,5 +17,16 @@ Expirations: See items that will expire soon
</p>
<p>
TODO: add items to your shopping list below
</p>
<p>
TODO: see expirted items below?
</p>
<p>
TODO: when no categories are found, show getting started, otherwise nit.
You will probably want to add some default Categories and Units
run TODO: https://pypi.org/project/django-smuggler/
</p>
{% endblock %}

View File

@ -0,0 +1,12 @@
{% extends 'inventory/base.html' %}
{% block content %}
<h2>Add Location</h2>
<form action="." method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit">
</form>
{% endblock %}

View File

@ -0,0 +1,13 @@
{% extends 'inventory/base.html' %}
{% block content %}
If you can not find the Category you want to add a new Line item from, add a new one <a href="../addcategory/">here</a>
<h2>Add Item Line</h2>
<form action="/additemline/" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit">
</form>
{% endblock %}

View File

@ -0,0 +1,17 @@
{% extends 'inventory/base.html' %}
{% block content %}
<p>
If you can not find the Pantry Item you want to add a new Line item from, add a new one <a href="../additem/">here</a>
</p>
<p>
If you can not find the Location you want to add a new Line item from, add a new one <a href="../addlocation/">here</a>
</p>
<h2>Add Item Line</h2>
<form action="/additemline/" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit">
</form>
{% endblock %}

View File

@ -0,0 +1,10 @@
{% extends 'inventory/base.html' %}
{% block content %}
<h2>Units</h2>
<ul>
{% for unit in object_list %}
<li>{{ unit.name }}</li>
{% endfor %}
</ul>
{% endblock %}

View File

@ -9,4 +9,9 @@ urlpatterns = [
path('consume/<pk>/', views.Consume.as_view(), name='consume'),
path('shoppinglist/', views.Shoppinglist.as_view(), name='shoppinglist'),
path('expirations/', views.Expirations.as_view(), name='expirations'),
path('units/', views.UnitView.as_view(), name='units'),
path('additemline/', views.PantryItemLineCreateView.as_view(), name='additemline'),
path('additem/', views.PantryItemCreateView.as_view(), name='additem'),
path('addcategory/', views.CategoryCreateView.as_view(), name='addcategory'),
path('addlocation/', views.LocationCreateView.as_view(), name='addlocation'),
]

View File

@ -3,7 +3,43 @@ from django.views import generic
from django.db.models import F, Sum, Q
from .models import PantryItem, PantryItemLine
from django.views.generic import ListView
from inventory.models import Unit, Location
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic.edit import CreateView
from .models import PantryItem, PantryItemLine, Category
class PantryItemLineCreateView(LoginRequiredMixin, CreateView):
model = PantryItemLine
fields = '__all__'
success_url = '.'
class PantryItemCreateView(LoginRequiredMixin, CreateView):
model = PantryItem
fields = '__all__'
success_url = '.'
class CategoryCreateView(LoginRequiredMixin, CreateView):
model = Category
fields = '__all__'
success_url = '.'
class LocationCreateView(LoginRequiredMixin, CreateView):
model = Location
fields = '__all__'
success_url = '.'
class UnitView(ListView):
model = Unit
# Create your views here.

0
users/__init__.py Normal file
View File

5
users/apps.py Normal file
View File

@ -0,0 +1,5 @@
from django.apps import AppConfig
class UsersConfig(AppConfig):
name = 'users'

5
users/forms.py Normal file
View File

@ -0,0 +1,5 @@
from django.contrib.auth.forms import UserCreationForm
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
fields = UserCreationForm.Meta.fields + ("email",)

View File

@ -0,0 +1,15 @@
{% extends 'inventory/base.html' %}
{% block content %}
<h2>Login</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Login">
</form>
<a href="{% url 'im:index' %}">Back to index</a>
<a href="{% url 'register' %}">Register</a>
<a href="{% url 'password_reset' %}">Reset Password</a>
{% endblock %}

View File

@ -0,0 +1,7 @@
{% extends 'base.html' %}
{% block content %}
<h2>Password changed</h2>
<a href="{% url 'im:index' %}">Back to index</a>
{% endblock %}

View File

@ -0,0 +1,13 @@
{% extends 'inventory/base.html' %}
{% block content %}
<h2>Change Password</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Change">
</form>
<a href="{% url 'im:index' %}">Back to index</a>
{% endblock %}

View File

@ -0,0 +1,8 @@
{% extends 'base.html' %}
{% block content %}
<h2>Password reset complete</h2>
<a href="{% url 'login' %}">Back to login</a>
{% endblock %}

View File

@ -0,0 +1,11 @@
{% extends 'base.html' %}
{% block content %}
<h2>Confirm password reset</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Confirm">
</form>
{% endblock %}

View File

@ -0,0 +1,7 @@
{% extends 'base.html' %}
{% block content %}
<h2>Password reset done</h2>
<a href="{% url 'login' %}">Back to login</a>
{% endblock %}

View File

@ -0,0 +1,13 @@
{% extends 'base.html' %}
{% block content %}
<h2>Send password reset link</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Reset">
</form>
<a href="{% url 'im:index' %}">Back to index</a>
{% endblock %}

View File

@ -0,0 +1,13 @@
{% extends 'base.html' %}
{% block content %}
<h2>Register</h2>
<form method="post">
{% csrf_token %}
{{form}}
<input type="submit" value="Register">
</form>
<a href="{% url 'login' %}">Back to login</a>
{% endblock %}

37
users/views.py Normal file
View File

@ -0,0 +1,37 @@
from django.contrib.auth import login
from django.shortcuts import redirect, render
from django.urls import reverse
from users.forms import CustomUserCreationForm
def dashboard(request):
return render(request, "users/dashboard.html")
def register(request):
if request.method == "GET":
return render(
request, "users/register.html",
{"form": CustomUserCreationForm}
)
elif request.method == "POST":
form = CustomUserCreationForm(request.POST)
if form.is_valid():
user = form.save()
login(request, user)
return redirect(reverse("index"))