backend setup
This commit is contained in:
parent
a748900ac1
commit
527d60c70c
0
bk_api/bills/__init__.py
Normal file
0
bk_api/bills/__init__.py
Normal file
6
bk_api/bills/admin.py
Normal file
6
bk_api/bills/admin.py
Normal file
@ -0,0 +1,6 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
from .models import Tag, Product, ProductOnBill, Receipt, ShopTag, Shop
|
||||
|
||||
admin.site.register([Tag, Product, ProductOnBill, Receipt, ShopTag, Shop])
|
5
bk_api/bills/apps.py
Normal file
5
bk_api/bills/apps.py
Normal file
@ -0,0 +1,5 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class BillsConfig(AppConfig):
|
||||
name = 'bills'
|
16
bk_api/bills/endpoints.py
Normal file
16
bk_api/bills/endpoints.py
Normal file
@ -0,0 +1,16 @@
|
||||
from django.conf.urls import include, url
|
||||
from rest_framework import routers
|
||||
|
||||
from .views import TagViewSet, ProductViewSet, ReceiptViewSet, ProductOnBillViewSet, ShopTagViewSet, ShopViewSet
|
||||
|
||||
router = routers.DefaultRouter()
|
||||
router.register('tags', TagViewSet)
|
||||
router.register('shop_tags', ShopTagViewSet)
|
||||
router.register('shops', ShopViewSet)
|
||||
router.register('products', ProductViewSet)
|
||||
router.register('products_on_bills', ProductOnBillViewSet)
|
||||
router.register('receipts', ReceiptViewSet)
|
||||
|
||||
urlpatterns = [
|
||||
url("^", include(router.urls)),
|
||||
]
|
0
bk_api/bills/management/__init__.py
Normal file
0
bk_api/bills/management/__init__.py
Normal file
0
bk_api/bills/management/commands/__init__.py
Normal file
0
bk_api/bills/management/commands/__init__.py
Normal file
34
bk_api/bills/management/commands/data.json
Normal file
34
bk_api/bills/management/commands/data.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"tags":[
|
||||
{"name": "owoce", "color": "green"},
|
||||
{"name": "warzywa", "color": "green"},
|
||||
{"name": "pieczywo", "color": "yellow"},
|
||||
{"name": "słodycze", "color": "blue"}
|
||||
],
|
||||
"shop_tags": [
|
||||
{"name": "sklep", "color": "green"},
|
||||
{"name": "stołówka", "color": "green"},
|
||||
{"name": "restauracja", "color": "green"}
|
||||
],
|
||||
"shops": [
|
||||
{"name": "Biedronka",
|
||||
"tags": [
|
||||
{"name": "sklep"}
|
||||
]},
|
||||
{"name": "Lidl",
|
||||
"tags": [
|
||||
{"name": "sklep"}
|
||||
]},
|
||||
{"name": "Piotr i Paweł",
|
||||
"tags": [
|
||||
{"name": "sklep"}
|
||||
]}
|
||||
],
|
||||
"products": [
|
||||
{"name": "banany", "price": 5.50, "tags": [{"name": "owoce"}]},
|
||||
{"name": "mandarynki", "price": 2.99, "tags": [{"name": "owoce"}]},
|
||||
{"name": "marchew", "price": 1.99, "tags": [{"name": "warzywa"}]},
|
||||
{"name": "bułka kajzerka", "price": 0.39, "tags": [{"name": "pieczywo"}]},
|
||||
{"name": "jogurt naturalny", "price": 1.59, "tags": [{"name": "nabiał", "color": "wihte"}]}
|
||||
]
|
||||
}
|
111
bk_api/bills/management/commands/populate_db.py
Normal file
111
bk_api/bills/management/commands/populate_db.py
Normal file
@ -0,0 +1,111 @@
|
||||
import json
|
||||
import random
|
||||
from datetime import date, timedelta
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from bills.serializers import TagSerializer, ShopTagSerializer, ShopSerializer, ReceiptSerializer
|
||||
|
||||
class Command(BaseCommand):
|
||||
args = '<foo bar ...>'
|
||||
help = 'our help string comes here'
|
||||
|
||||
def _load_data(self):
|
||||
with open("./bills/management/commands/data.json", 'r') as json_file:
|
||||
self.data = json.load(json_file)
|
||||
|
||||
def _user_exists(self, username):
|
||||
return User.objects.filter(username=username).exists()
|
||||
|
||||
def _create_user(self, username: str):
|
||||
password = f"{username}_pass"
|
||||
user_exists = self._user_exists(username)
|
||||
|
||||
if user_exists:
|
||||
if input(f">: Delete {username} from db? [y/N]: ") != 'y':
|
||||
return None
|
||||
else:
|
||||
User.objects.get(username=username).delete()
|
||||
self.stdout.write(f"> User '{username}' deleted!")
|
||||
|
||||
user = User.objects.create_user(username, "", password)
|
||||
self.stdout.write(f"> Created user '{username}' with password '{password}'")
|
||||
return user
|
||||
|
||||
def _create_tags(self, user):
|
||||
created_tags = []
|
||||
for tag in self.data["tags"]:
|
||||
created_tag = TagSerializer(data=tag)
|
||||
created_tag.is_valid()
|
||||
created_tag.save(owner=user)
|
||||
self.stdout.write(f"> Created tag: '{created_tag.data['name']}'")
|
||||
created_tags.append(created_tag.data['name'])
|
||||
|
||||
self.stdout.write(f"> Created tags")
|
||||
return created_tags
|
||||
|
||||
def _create_shop_tags(self, user):
|
||||
created_tags = []
|
||||
for tag in self.data["shop_tags"]:
|
||||
created_tag = ShopTagSerializer(data=tag)
|
||||
created_tag.is_valid()
|
||||
created_tag.save(owner=user)
|
||||
self.stdout.write(f"> Created shop tag: '{created_tag.data['name']}'")
|
||||
created_tags.append(created_tag.data['name'])
|
||||
|
||||
self.stdout.write(f"> Created shop tags")
|
||||
return created_tags
|
||||
|
||||
|
||||
def _create_shops(self, user, shop_tags):
|
||||
created_shops = []
|
||||
for shop in self.data["shops"]:
|
||||
created_shop = ShopSerializer(data=shop)
|
||||
created_shop.is_valid()
|
||||
created_shop.save(owner=user)
|
||||
self.stdout.write(f"> Created shop: '{created_shop.data['name']}'")
|
||||
created_shops.append(created_shop.data)
|
||||
|
||||
self.stdout.write(f"> Created shop")
|
||||
return created_shops
|
||||
|
||||
def _create_receipts(self, user, shops, tags, shop_tags):
|
||||
# dates for last 30 days
|
||||
for d in [date.today() - timedelta(31) + timedelta(n)for n in range(31)]:
|
||||
if random.random() > 0.4:
|
||||
continue
|
||||
receipt_date = f"{d.year}-{d.month}-{d.day}"
|
||||
receipt_schop = random.choice(shops)
|
||||
receipt_products = [random.choice(self.data["products"])]
|
||||
|
||||
for product in self.data["products"]:
|
||||
if random.random() < 0.20:
|
||||
receipt_products.append(product)
|
||||
|
||||
new_receipt_data = {
|
||||
"shop": receipt_schop,
|
||||
"date": receipt_date,
|
||||
"products": receipt_products
|
||||
}
|
||||
|
||||
created_receipt = ReceiptSerializer(data=new_receipt_data)
|
||||
is_valid = created_receipt.is_valid()
|
||||
if not is_valid:
|
||||
print(created_receipt.errors)
|
||||
break;
|
||||
created_receipt.save(owner=user)
|
||||
self.stdout.write(f"> Created receipt: {receipt_date} | {receipt_schop['name']}")
|
||||
|
||||
|
||||
|
||||
def handle(self, *args, **options):
|
||||
self.stdout.write(f"_/-\__/-\_POPULATE DB _/-\__/-\_")
|
||||
user = self._create_user("demo_user")
|
||||
if user != None:
|
||||
self._load_data()
|
||||
tags = self._create_tags(user)
|
||||
shop_tags = self._create_shop_tags(user)
|
||||
shops = self._create_shops(user, shop_tags)
|
||||
self._create_receipts(user,shops, tags, shop_tags)
|
||||
self.stdout.write(f"_/-\__/-\_ DONE _/-\__/-\_")
|
80
bk_api/bills/migrations/0001_initial.py
Normal file
80
bk_api/bills/migrations/0001_initial.py
Normal file
@ -0,0 +1,80 @@
|
||||
# Generated by Django 3.0 on 2020-01-05 12:40
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Tag',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=30)),
|
||||
('color', models.CharField(default='#f2f2f2', max_length=30)),
|
||||
('created_at', models.DateField(auto_now_add=True)),
|
||||
('owner', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='tags', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ShopTag',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=30)),
|
||||
('color', models.CharField(default='#f2f2f2', max_length=30)),
|
||||
('created_at', models.DateField(auto_now_add=True)),
|
||||
('owner', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='shop_tags', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Shop',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=30)),
|
||||
('created_at', models.DateField(auto_now_add=True)),
|
||||
('owner', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='shops', to=settings.AUTH_USER_MODEL)),
|
||||
('tags', models.ManyToManyField(blank=True, to='bills.ShopTag')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Receipt',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created_at', models.DateField(auto_now_add=True)),
|
||||
('date', models.DateField()),
|
||||
('total_price', models.FloatField(default=0.0)),
|
||||
('owner', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='receipts', to=settings.AUTH_USER_MODEL)),
|
||||
('shop', models.ForeignKey(blank=True, on_delete=django.db.models.deletion.CASCADE, related_name='receipts', to='bills.Shop')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ProductOnBill',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=30)),
|
||||
('created_at', models.DateField(auto_now_add=True)),
|
||||
('price', models.DecimalField(decimal_places=2, max_digits=5)),
|
||||
('owner', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='products_on_bills', to=settings.AUTH_USER_MODEL)),
|
||||
('receipt', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='products', to='bills.Receipt')),
|
||||
('tags', models.ManyToManyField(blank=True, to='bills.Tag')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Product',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=30)),
|
||||
('created_at', models.DateField(auto_now_add=True)),
|
||||
('default_tags', models.ManyToManyField(blank=True, to='bills.Tag')),
|
||||
('owner', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='products', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
0
bk_api/bills/migrations/__init__.py
Normal file
0
bk_api/bills/migrations/__init__.py
Normal file
66
bk_api/bills/models.py
Normal file
66
bk_api/bills/models.py
Normal file
@ -0,0 +1,66 @@
|
||||
from django.db import models
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
class Tag(models.Model):
|
||||
name = models.CharField(max_length=30)
|
||||
color = models.CharField(max_length=30, default="#f2f2f2")
|
||||
created_at = models.DateField(auto_now_add=True)
|
||||
owner = models.ForeignKey(User, related_name="tags", on_delete=models.CASCADE, null=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name} | {self.owner.username}"
|
||||
|
||||
|
||||
class ShopTag(models.Model):
|
||||
name = models.CharField(max_length=30)
|
||||
color = models.CharField(max_length=30, default="#9e9e9e")
|
||||
created_at = models.DateField(auto_now_add=True)
|
||||
owner = models.ForeignKey(User, related_name="shop_tags", on_delete=models.CASCADE, null=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name} | {self.owner.username}"
|
||||
|
||||
|
||||
class Shop(models.Model):
|
||||
name = models.CharField(max_length=30)
|
||||
created_at = models.DateField(auto_now_add=True)
|
||||
tags = models.ManyToManyField(ShopTag, blank=True)
|
||||
owner = models.ForeignKey(User, related_name="shops", on_delete=models.CASCADE, null=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name} | {self.owner.username}"
|
||||
|
||||
|
||||
class Product(models.Model):
|
||||
name = models.CharField(max_length=30)
|
||||
created_at = models.DateField(auto_now_add=True)
|
||||
owner = models.ForeignKey(User, related_name="products", on_delete=models.CASCADE, null=True)
|
||||
default_tags = models.ManyToManyField(Tag, blank=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name} | {self.owner.username}"
|
||||
|
||||
|
||||
class Receipt(models.Model):
|
||||
shop = models.ForeignKey(Shop, related_name="receipts", on_delete=models.CASCADE, blank=True)
|
||||
created_at = models.DateField(auto_now_add=True)
|
||||
date = models.DateField(auto_now_add=False)
|
||||
owner = models.ForeignKey(User, related_name="receipts", on_delete=models.CASCADE, null=True)
|
||||
total_price = models.FloatField(default=float(0.00))
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.shop} | {self.total_price} zł | {self.owner.username}"
|
||||
|
||||
|
||||
class ProductOnBill(models.Model):
|
||||
name = models.CharField(max_length=30)
|
||||
created_at = models.DateField(auto_now_add=True)
|
||||
price = models.DecimalField(max_digits=5, decimal_places=2)
|
||||
receipt = models.ForeignKey(Receipt, related_name="products", on_delete=models.CASCADE)
|
||||
tags = models.ManyToManyField(Tag, blank=True)
|
||||
owner = models.ForeignKey(User, related_name="products_on_bills", on_delete=models.CASCADE, null=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name} | {self.price} zł | {self.owner.username}"
|
||||
|
107
bk_api/bills/serializers.py
Normal file
107
bk_api/bills/serializers.py
Normal file
@ -0,0 +1,107 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
from .models import Tag, Product, ProductOnBill, Receipt, ShopTag, Shop
|
||||
|
||||
|
||||
class TagSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Tag
|
||||
fields = ('name', 'color', 'pk')
|
||||
|
||||
|
||||
class ShopTagSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = ShopTag
|
||||
fields = ('name', 'color', 'pk')
|
||||
|
||||
|
||||
class ShopSerializer(serializers.ModelSerializer):
|
||||
tags = ShopTagSerializer(many=True)
|
||||
|
||||
class Meta:
|
||||
model = Shop
|
||||
fields = ('pk', 'name', 'tags')
|
||||
|
||||
def create(self, validated_data):
|
||||
tags_data = validated_data.pop("tags")
|
||||
shop_data = Shop.objects.create(**validated_data)
|
||||
shop_data.save()
|
||||
|
||||
for tag in tags_data:
|
||||
tag_ref, _ = ShopTag.objects.get_or_create(name=tag["name"], owner=validated_data["owner"])
|
||||
shop_data.tags.add(tag_ref)
|
||||
return shop_data
|
||||
|
||||
|
||||
class ProductSerializer(serializers.ModelSerializer):
|
||||
default_tags = TagSerializer(many=True)
|
||||
|
||||
class Meta:
|
||||
model = Product
|
||||
fields = ('pk', 'name', 'default_tags')
|
||||
|
||||
def create(self, validated_data):
|
||||
default_tags_data = validated_data.pop("default_tags")
|
||||
product_data = Product.objects.create(**validated_data)
|
||||
product_data.save()
|
||||
|
||||
for tag in default_tags_data:
|
||||
tag_ref, _ = Tag.objects.get_or_create(name=tag["name"], owner=self.context['request'].user)
|
||||
product_data.default_tags.add(tag_ref)
|
||||
|
||||
return product_data
|
||||
|
||||
|
||||
class ProductOnBillSerializer(serializers.ModelSerializer):
|
||||
tags = TagSerializer(many=True)
|
||||
|
||||
class Meta:
|
||||
model = ProductOnBill
|
||||
fields = ['pk', 'name', 'price', 'tags']
|
||||
|
||||
|
||||
class ReceiptSerializer(serializers.ModelSerializer):
|
||||
products = ProductOnBillSerializer(many=True)
|
||||
shop = ShopSerializer()
|
||||
|
||||
class Meta:
|
||||
model = Receipt
|
||||
fields = ['pk', 'shop', 'date', 'products', 'total_price']
|
||||
|
||||
def create(self, validated_data):
|
||||
owner_data = validated_data.pop("owner")
|
||||
products_data = validated_data.pop("products")
|
||||
shop_data = validated_data.pop("shop")
|
||||
total_price_data = 0
|
||||
|
||||
# get total price of products
|
||||
for p in products_data:
|
||||
total_price_data += p["price"]
|
||||
|
||||
# create shop if it does not exist yet
|
||||
shop_ref, _ = Shop.objects.get_or_create(name=shop_data["name"], owner=owner_data)
|
||||
|
||||
receipt = Receipt.objects.create(owner=owner_data, total_price=total_price_data, shop=shop_ref, **validated_data)
|
||||
|
||||
for p in products_data:
|
||||
# create product if it does not exists in products base
|
||||
product_data, created = Product.objects.get_or_create(name=p["name"], owner=owner_data)
|
||||
tags_data = p.pop("tags")
|
||||
|
||||
# create product on bill record
|
||||
created_product_on_bill = ProductOnBill.objects.create(owner=owner_data, receipt=receipt, **p)
|
||||
|
||||
for tag in tags_data:
|
||||
tag_ref, _ = Tag.objects.get_or_create(name=tag["name"], owner=owner_data )
|
||||
created_product_on_bill.tags.add(tag_ref)
|
||||
|
||||
# if it's new product, set present tags as default tags
|
||||
if created:
|
||||
product_data.default_tags.add(tag_ref)
|
||||
|
||||
return receipt
|
||||
|
||||
|
||||
|
||||
|
||||
|
3
bk_api/bills/tests.py
Normal file
3
bk_api/bills/tests.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
79
bk_api/bills/views.py
Normal file
79
bk_api/bills/views.py
Normal file
@ -0,0 +1,79 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
from rest_framework import viewsets, permissions, pagination
|
||||
|
||||
from .models import Tag, Product, ProductOnBill, Receipt, Shop, ShopTag
|
||||
from .serializers import TagSerializer, ProductSerializer, ProductOnBillSerializer, ReceiptSerializer, ShopSerializer, ShopTagSerializer
|
||||
|
||||
|
||||
class TagViewSet(viewsets.ModelViewSet):
|
||||
queryset = Tag.objects.all()
|
||||
# permission_classes = [permissions.AllowAny]
|
||||
serializer_class = TagSerializer
|
||||
def get_queryset(self):
|
||||
return self.request.user.tags.all()
|
||||
|
||||
def perform_create(self, serializer):
|
||||
serializer.save(owner=self.request.user)
|
||||
|
||||
|
||||
class ShopTagViewSet(viewsets.ModelViewSet):
|
||||
queryset = ShopTag.objects.all()
|
||||
# permission_classes = [permissions.AllowAny]
|
||||
serializer_class = ShopTagSerializer
|
||||
def get_queryset(self):
|
||||
return self.request.user.shop_tags.all()
|
||||
|
||||
def perform_create(self, serializer):
|
||||
serializer.save(owner=self.request.user)
|
||||
|
||||
|
||||
class ShopViewSet(viewsets.ModelViewSet):
|
||||
queryset = Shop.objects.all()
|
||||
# permission_classes = [permissions.AllowAny]
|
||||
serializer_class = ShopSerializer
|
||||
def get_queryset(self):
|
||||
return self.request.user.shops.all()
|
||||
|
||||
def perform_create(self, serializer):
|
||||
serializer.save(owner=self.request.user)
|
||||
|
||||
|
||||
class ProductViewSet(viewsets.ModelViewSet):
|
||||
queryset = Product.objects.all()
|
||||
# permission_classes = [permissions.AllowAny]
|
||||
serializer_class = ProductSerializer
|
||||
def get_queryset(self):
|
||||
return self.request.user.products.all()
|
||||
|
||||
def perform_create(self, serializer):
|
||||
serializer.save(owner=self.request.user)
|
||||
|
||||
|
||||
class ProductOnBillViewSet(viewsets.ModelViewSet):
|
||||
queryset = ProductOnBill.objects.all()
|
||||
# permission_classes = [permissions.AllowAny]
|
||||
serializer_class = ProductOnBillSerializer
|
||||
def get_queryset(self):
|
||||
return self.request.user.products_on_bills.all()
|
||||
|
||||
def perform_create(self, serializer):
|
||||
serializer.save(owner=self.request.user)
|
||||
|
||||
|
||||
|
||||
class StandardResultsSetPagination(pagination.PageNumberPagination):
|
||||
page_size = 10
|
||||
page_size_query_param = 'page_size'
|
||||
|
||||
|
||||
class ReceiptViewSet(viewsets.ModelViewSet):
|
||||
queryset = Receipt.objects.all()
|
||||
serializer_class = ReceiptSerializer
|
||||
pagination_class = StandardResultsSetPagination
|
||||
|
||||
def get_queryset(self):
|
||||
return self.request.user.receipts.all()
|
||||
|
||||
def perform_create(self, serializer):
|
||||
serializer.save(owner=self.request.user)
|
@ -25,12 +25,23 @@ SECRET_KEY = 'i(12@f48%x!p8q^4gbn3++@^$g45!os)+3=8p0hf4g)j)5bqmf'
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
# ALLOWED_HOSTS = ["api.app.localhost.pl"]
|
||||
ALLOWED_HOSTS = []
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
'DEFAULT_PERMISSION_CLASSES': [
|
||||
'rest_framework.permissions.IsAuthenticated',
|
||||
# 'rest_framework.permissions.AllowAny',
|
||||
],
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': ('knox.auth.TokenAuthentication', 'rest_framework.authentication.SessionAuthentication'),
|
||||
# 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
|
||||
# 'PAGE_SIZE': 10
|
||||
}
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'bills',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
@ -38,6 +49,9 @@ INSTALLED_APPS = [
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'corsheaders',
|
||||
'rest_framework',
|
||||
'knox'
|
||||
# 'rest_framework.authtoken'
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
@ -116,11 +130,19 @@ USE_L10N = True
|
||||
USE_TZ = True
|
||||
|
||||
CSRF_COOKIE_SECURE = False
|
||||
# CSRF_COOKIE_NAME = "XSRF-TOKEN"
|
||||
# CSRF_COOKIE_DOMAIN = "localhost.pl"
|
||||
# CSRF_COOKIE_SAMESITE = None
|
||||
|
||||
CORS_ORIGIN_ALLOW_ALL = True
|
||||
CORS_ALLOW_CREDENTIALS = True
|
||||
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/2.2/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
|
||||
|
||||
|
@ -16,10 +16,24 @@ Including another URLconf
|
||||
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
||||
from django.contrib import admin
|
||||
from django.urls import include, path
|
||||
from django.conf.urls import url
|
||||
|
||||
|
||||
|
||||
from knox import views as knox_views
|
||||
from .views import LoginView
|
||||
# from rest_framework.authtoken import views
|
||||
from bills import endpoints
|
||||
|
||||
urlpatterns = [
|
||||
path('bills/', include('core.urls')),
|
||||
# path('bills/', include('core.urls')),
|
||||
path('admin/', admin.site.urls),
|
||||
url('^api/', include(endpoints)),
|
||||
# url(r'^api/auth/', views.obtain_auth_token)
|
||||
# url(r'api/auth/', include('knox.urls'))
|
||||
url(r'api/auth/login/', LoginView.as_view(), name='knox_login'),
|
||||
url(r'api/auth/logout/', knox_views.LogoutView.as_view(), name='knox_logout'),
|
||||
url(r'api/auth/logoutall/', knox_views.LogoutAllView.as_view(), name='knox_logoutall'),
|
||||
]
|
||||
|
||||
urlpatterns += staticfiles_urlpatterns()
|
||||
|
14
bk_api/bk_api/views.py
Normal file
14
bk_api/bk_api/views.py
Normal file
@ -0,0 +1,14 @@
|
||||
from django.contrib.auth import login
|
||||
from rest_framework import permissions
|
||||
from rest_framework.authtoken.serializers import AuthTokenSerializer
|
||||
from knox.views import LoginView as KnoxLoginView
|
||||
|
||||
class LoginView(KnoxLoginView):
|
||||
permission_classes = (permissions.AllowAny,)
|
||||
|
||||
def post(self, request, format=None):
|
||||
serializer = AuthTokenSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
user = serializer.validated_data['user']
|
||||
login(request, user)
|
||||
return super(LoginView, self).post(request, format=None)
|
1
bk_webapp/.env
Normal file
1
bk_webapp/.env
Normal file
@ -0,0 +1 @@
|
||||
API_URL=http://localhost:8000
|
5
bk_webapp/package-lock.json
generated
5
bk_webapp/package-lock.json
generated
@ -8038,6 +8038,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"js-cookie": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz",
|
||||
"integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ=="
|
||||
},
|
||||
"js-levenshtein": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz",
|
||||
|
@ -7,6 +7,7 @@
|
||||
"@testing-library/react": "^9.3.2",
|
||||
"@testing-library/user-event": "^7.1.2",
|
||||
"axios": "^0.19.0",
|
||||
"js-cookie": "^2.2.1",
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0",
|
||||
"react-minimal-pie-chart": "^6.0.1",
|
||||
|
@ -1,54 +0,0 @@
|
||||
import React from "react";
|
||||
import {
|
||||
Button,
|
||||
Form,
|
||||
Grid,
|
||||
Segment,
|
||||
Container,
|
||||
Image
|
||||
} from "semantic-ui-react";
|
||||
import { useHistory } from "react-router-dom";
|
||||
|
||||
import logo from "../../img/logo_project.svg";
|
||||
import "./Login.css";
|
||||
|
||||
function Login() {
|
||||
let history = useHistory();
|
||||
return (
|
||||
<Container className="login-container">
|
||||
<Grid columns={1} verticalAlign="middle" style={{ height: "100%" }}>
|
||||
<Grid.Column>
|
||||
<Image src={logo} size="medium" centered />
|
||||
<Segment>
|
||||
<Form size="large">
|
||||
<Form.Input
|
||||
fluid
|
||||
icon="user"
|
||||
iconPosition="left"
|
||||
placeholder="Email address"
|
||||
/>
|
||||
<Form.Input
|
||||
fluid
|
||||
icon="lock"
|
||||
iconPosition="left"
|
||||
placeholder="Password"
|
||||
type="password"
|
||||
/>
|
||||
<Button
|
||||
basic
|
||||
fluid
|
||||
color="yellow"
|
||||
size="large"
|
||||
onClick={() => history.push("/home")}
|
||||
>
|
||||
Login
|
||||
</Button>
|
||||
</Form>
|
||||
</Segment>
|
||||
</Grid.Column>
|
||||
</Grid>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
export default Login;
|
107
bk_webapp/src/screens/Login/Login.jsx
Normal file
107
bk_webapp/src/screens/Login/Login.jsx
Normal file
@ -0,0 +1,107 @@
|
||||
import React, { useState } from "react";
|
||||
import {
|
||||
Button,
|
||||
Form,
|
||||
Grid,
|
||||
Segment,
|
||||
Container,
|
||||
Image
|
||||
} from "semantic-ui-react";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import axios from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
import logo from "../../img/logo_project.svg";
|
||||
import "./Login.css";
|
||||
|
||||
function Login() {
|
||||
const [username, setUsername] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const history = useHistory();
|
||||
|
||||
const handleSubmit = () => {
|
||||
// console.log(process.env);
|
||||
const bodyFormData = new FormData();
|
||||
bodyFormData.set("username", username);
|
||||
bodyFormData.set("password", password);
|
||||
|
||||
axios({
|
||||
method: "get",
|
||||
url: "http://api.app.localhost.pl/api-auth/login/",
|
||||
withCredentials: true
|
||||
// data: bodyFormData,
|
||||
// headers: { "Content-Type": "multipart/form-data" }
|
||||
})
|
||||
.then(function(response) {
|
||||
//handle success
|
||||
console.log("success");
|
||||
const csrfToken = Cookies.get("csrftoken");
|
||||
console.log(csrfToken);
|
||||
axios({
|
||||
method: "post",
|
||||
url: "http://api.app.localhost.pl/api-auth/login/",
|
||||
withCredentials: true,
|
||||
data: bodyFormData,
|
||||
// headers: { "X-CSRFToken": csrfToken },
|
||||
xsrfCookieName: "XSRF-TOKEN",
|
||||
xsrfHeaderName: "X-CSRFToken"
|
||||
})
|
||||
.then(resp => {
|
||||
console.log("success x 2!!!");
|
||||
console.log(resp);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
});
|
||||
})
|
||||
.catch(function(response) {
|
||||
//handle error
|
||||
console.log("error");
|
||||
console.log(response);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Container className="login-container">
|
||||
<Grid columns={1} verticalAlign="middle" style={{ height: "100%" }}>
|
||||
<Grid.Column>
|
||||
<Image src={logo} size="medium" centered />
|
||||
<Segment>
|
||||
<Form size="large">
|
||||
<Form.Input
|
||||
fluid
|
||||
icon="user"
|
||||
iconPosition="left"
|
||||
placeholder="Nawa użytkownika"
|
||||
onChange={e => {
|
||||
setUsername(e.target.value);
|
||||
}}
|
||||
/>
|
||||
<Form.Input
|
||||
fluid
|
||||
icon="lock"
|
||||
iconPosition="left"
|
||||
placeholder="Hasło"
|
||||
type="password"
|
||||
onChange={e => {
|
||||
setPassword(e.target.value);
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
basic
|
||||
fluid
|
||||
color="yellow"
|
||||
size="large"
|
||||
onClick={() => handleSubmit()}
|
||||
>
|
||||
Login
|
||||
</Button>
|
||||
</Form>
|
||||
</Segment>
|
||||
</Grid.Column>
|
||||
</Grid>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
export default Login;
|
Loading…
Reference in New Issue
Block a user