├── basket ├── __init__.py ├── tests │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-39.pyc │ │ └── test_views.cpython-39.pyc │ └── test_views.py ├── migrations │ ├── __init__.py │ └── __pycache__ │ │ └── __init__.cpython-39.pyc ├── apps.py ├── context_processors.py ├── __pycache__ │ ├── urls.cpython-39.pyc │ ├── basket.cpython-39.pyc │ ├── models.cpython-39.pyc │ ├── views.cpython-39.pyc │ ├── __init__.cpython-39.pyc │ └── context_processors.cpython-39.pyc ├── urls.py ├── views.py └── basket.py ├── core ├── __init__.py ├── db.sqlite3 ├── settings │ ├── __init__.py │ ├── __pycache__ │ │ ├── base.cpython-39.pyc │ │ ├── core.cpython-39.pyc │ │ ├── __init__.cpython-39.pyc │ │ └── dev_debug.cpython-39.pyc │ ├── dev_debug.py │ └── base.py ├── __pycache__ │ ├── urls.cpython-39.pyc │ ├── wsgi.cpython-39.pyc │ ├── __init__.cpython-39.pyc │ └── settings.cpython-39.pyc ├── asgi.py ├── wsgi.py └── urls.py ├── orders ├── __init__.py ├── migrations │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-39.pyc │ │ ├── 0001_initial.cpython-39.pyc │ │ └── 0002_remove_order_email.cpython-39.pyc │ └── 0001_initial.py ├── tests.py ├── apps.py ├── __pycache__ │ ├── urls.cpython-39.pyc │ ├── admin.cpython-39.pyc │ ├── models.cpython-39.pyc │ ├── tests.cpython-39.pyc │ ├── views.cpython-39.pyc │ └── __init__.cpython-39.pyc ├── admin.py ├── urls.py ├── views.py └── models.py ├── payment ├── tests.py ├── __init__.py ├── migrations │ ├── __init__.py │ └── __pycache__ │ │ └── __init__.cpython-39.pyc ├── models.py ├── admin.py ├── apps.py ├── __pycache__ │ ├── tests.cpython-39.pyc │ ├── urls.cpython-39.pyc │ ├── views.cpython-39.pyc │ └── __init__.cpython-39.pyc ├── urls.py └── views.py ├── store ├── __init__.py ├── tests │ ├── __init__.py │ ├── __pycache__ │ │ ├── tests.cpython-39.pyc │ │ ├── __init__.cpython-39.pyc │ │ ├── test_models.cpython-39.pyc │ │ └── test_views.cpython-39.pyc │ ├── test_models.py │ └── test_views.py ├── migrations │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-39.pyc │ │ ├── 0001_initial.cpython-39.pyc │ │ ├── 0002_product_is_active.cpython-39.pyc │ │ ├── 0003_imagealbum_name.cpython-39.pyc │ │ ├── 0002_auto_20201221_1612.cpython-39.pyc │ │ ├── 0002_auto_20210130_0004.cpython-39.pyc │ │ ├── 0003_auto_20201223_1409.cpython-39.pyc │ │ ├── 0004_auto_20201224_0015.cpython-39.pyc │ │ └── 0004_auto_20210129_1731.cpython-39.pyc │ └── 0001_initial.py ├── apps.py ├── __pycache__ │ ├── admin.cpython-39.pyc │ ├── urls.cpython-39.pyc │ ├── views.cpython-39.pyc │ ├── __init__.cpython-39.pyc │ ├── models.cpython-39.pyc │ └── context_processors.cpython-39.pyc ├── context_processors.py ├── urls.py ├── views.py ├── admin.py └── models.py ├── account ├── __init__.py ├── migrations │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-39.pyc │ │ ├── 0001_initial.cpython-39.pyc │ │ └── 0002_userbase_is_staff.cpython-39.pyc │ └── 0001_initial.py ├── tests.py ├── apps.py ├── admin.py ├── __pycache__ │ ├── admin.cpython-39.pyc │ ├── forms.cpython-39.pyc │ ├── models.cpython-39.pyc │ ├── tests.cpython-39.pyc │ ├── tokens.cpython-39.pyc │ ├── urls.cpython-39.pyc │ ├── views.cpython-39.pyc │ └── __init__.cpython-39.pyc ├── templatetags │ ├── __pycache__ │ │ └── example.cpython-39.pyc │ └── example.py ├── tokens.py ├── urls.py ├── models.py ├── views.py └── forms.py ├── static ├── basket │ └── css │ │ └── basket.css ├── store │ └── css │ │ └── store.css ├── logo.png ├── account │ └── css │ │ └── account.css ├── payment │ ├── css │ │ └── payment.css │ └── index.js └── core │ └── css │ └── base.css ├── .gitattributes ├── db.sqlite3 ├── _documentation ├── stripe.txt ├── commands.txt ├── packages.txt ├── vscode_settings.txt └── database_schema.txt ├── media └── images │ ├── default.png │ ├── img1_DCytNvp.png │ ├── img2_SUlRxwK.png │ ├── default_7j3pLDD.png │ ├── default_AN2mWQr.png │ └── img1_DCytNvp_NlI9SCz.png ├── templates ├── two_factor │ ├── twilio │ │ └── sms_message.html │ ├── _wizard_forms.html │ ├── _base_focus.html │ ├── _base.html │ ├── _wizard_actions.html │ ├── profile │ │ ├── disable.html │ │ └── profile.html │ └── core │ │ ├── otp_required.html │ │ ├── phone_register.html │ │ ├── setup_complete.html │ │ ├── backup_tokens.html │ │ ├── login.html │ │ └── setup.html ├── account │ ├── registration │ │ ├── account_activation_email.html │ │ ├── activation_invalid.html │ │ ├── register_email_confirm.html │ │ └── register.html │ ├── dashboard │ │ ├── delete_confirm.html │ │ ├── edit_addresses.html │ │ ├── edit_details.html │ │ ├── addresses.html │ │ └── dashboard.html │ ├── sub_base.html │ ├── password_reset │ │ ├── reset_status.html │ │ ├── password_reset_email.html │ │ ├── password_reset_form.html │ │ └── password_reset_confirm.html │ └── login.html ├── payment │ ├── error.html │ ├── orderplaced.html │ ├── sub_base.html │ └── payment_form.html ├── store │ ├── category.html │ ├── index.html │ └── single.html ├── basket │ └── summary.html └── base.html ├── requirements.txt ├── README.md ├── .vscode └── settings.json ├── manage.py └── LICENSE /basket/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /core/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /core/db.sqlite3: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /orders/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /payment/tests.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /store/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /account/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /payment/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /store/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /basket/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /core/settings/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/basket/css/basket.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /store/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /account/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /basket/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /orders/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /payment/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /account/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /orders/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /payment/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /payment/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /static/store/css/store.css: -------------------------------------------------------------------------------- 1 | .store-select-dropdown{ 2 | width:50px; 3 | height:40px; 4 | } -------------------------------------------------------------------------------- /db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/db.sqlite3 -------------------------------------------------------------------------------- /_documentation/stripe.txt: -------------------------------------------------------------------------------- 1 | No auth: 4242424242424242 2 | Auth: 4000002500003155 3 | Error: 4000000000009995 -------------------------------------------------------------------------------- /static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/static/logo.png -------------------------------------------------------------------------------- /store/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class StoreConfig(AppConfig): 5 | name = 'store' 6 | -------------------------------------------------------------------------------- /basket/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class BasketConfig(AppConfig): 5 | name = 'basket' 6 | -------------------------------------------------------------------------------- /orders/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class OrdersConfig(AppConfig): 5 | name = 'orders' 6 | -------------------------------------------------------------------------------- /account/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AccountConfig(AppConfig): 5 | name = 'account' 6 | -------------------------------------------------------------------------------- /media/images/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/media/images/default.png -------------------------------------------------------------------------------- /payment/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class PaymentConfig(AppConfig): 5 | name = 'payment' 6 | -------------------------------------------------------------------------------- /account/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from .models import Customer 4 | 5 | admin.site.register(Customer) 6 | -------------------------------------------------------------------------------- /basket/context_processors.py: -------------------------------------------------------------------------------- 1 | from .basket import Basket 2 | 3 | 4 | def basket(request): 5 | return {'basket': Basket(request)} 6 | -------------------------------------------------------------------------------- /media/images/img1_DCytNvp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/media/images/img1_DCytNvp.png -------------------------------------------------------------------------------- /media/images/img2_SUlRxwK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/media/images/img2_SUlRxwK.png -------------------------------------------------------------------------------- /media/images/default_7j3pLDD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/media/images/default_7j3pLDD.png -------------------------------------------------------------------------------- /media/images/default_AN2mWQr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/media/images/default_AN2mWQr.png -------------------------------------------------------------------------------- /_documentation/commands.txt: -------------------------------------------------------------------------------- 1 | # View all migrations 2 | py manage.py makemigrations --check 3 | 4 | # Migrations 5 | python manage.py showmigrations -------------------------------------------------------------------------------- /core/__pycache__/urls.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/core/__pycache__/urls.cpython-39.pyc -------------------------------------------------------------------------------- /core/__pycache__/wsgi.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/core/__pycache__/wsgi.cpython-39.pyc -------------------------------------------------------------------------------- /basket/__pycache__/urls.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/basket/__pycache__/urls.cpython-39.pyc -------------------------------------------------------------------------------- /media/images/img1_DCytNvp_NlI9SCz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/media/images/img1_DCytNvp_NlI9SCz.png -------------------------------------------------------------------------------- /orders/__pycache__/urls.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/orders/__pycache__/urls.cpython-39.pyc -------------------------------------------------------------------------------- /store/__pycache__/admin.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/store/__pycache__/admin.cpython-39.pyc -------------------------------------------------------------------------------- /store/__pycache__/urls.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/store/__pycache__/urls.cpython-39.pyc -------------------------------------------------------------------------------- /store/__pycache__/views.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/store/__pycache__/views.cpython-39.pyc -------------------------------------------------------------------------------- /_documentation/packages.txt: -------------------------------------------------------------------------------- 1 | Package List 2 | #### 3 | 4 | django 5 | black 6 | isort 7 | django-mptt 8 | pillow 9 | stripe 10 | coverage 11 | six -------------------------------------------------------------------------------- /account/__pycache__/admin.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/account/__pycache__/admin.cpython-39.pyc -------------------------------------------------------------------------------- /account/__pycache__/forms.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/account/__pycache__/forms.cpython-39.pyc -------------------------------------------------------------------------------- /account/__pycache__/models.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/account/__pycache__/models.cpython-39.pyc -------------------------------------------------------------------------------- /account/__pycache__/tests.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/account/__pycache__/tests.cpython-39.pyc -------------------------------------------------------------------------------- /account/__pycache__/tokens.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/account/__pycache__/tokens.cpython-39.pyc -------------------------------------------------------------------------------- /account/__pycache__/urls.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/account/__pycache__/urls.cpython-39.pyc -------------------------------------------------------------------------------- /account/__pycache__/views.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/account/__pycache__/views.cpython-39.pyc -------------------------------------------------------------------------------- /basket/__pycache__/basket.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/basket/__pycache__/basket.cpython-39.pyc -------------------------------------------------------------------------------- /basket/__pycache__/models.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/basket/__pycache__/models.cpython-39.pyc -------------------------------------------------------------------------------- /basket/__pycache__/views.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/basket/__pycache__/views.cpython-39.pyc -------------------------------------------------------------------------------- /core/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/core/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /core/__pycache__/settings.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/core/__pycache__/settings.cpython-39.pyc -------------------------------------------------------------------------------- /orders/__pycache__/admin.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/orders/__pycache__/admin.cpython-39.pyc -------------------------------------------------------------------------------- /orders/__pycache__/models.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/orders/__pycache__/models.cpython-39.pyc -------------------------------------------------------------------------------- /orders/__pycache__/tests.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/orders/__pycache__/tests.cpython-39.pyc -------------------------------------------------------------------------------- /orders/__pycache__/views.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/orders/__pycache__/views.cpython-39.pyc -------------------------------------------------------------------------------- /payment/__pycache__/tests.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/payment/__pycache__/tests.cpython-39.pyc -------------------------------------------------------------------------------- /payment/__pycache__/urls.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/payment/__pycache__/urls.cpython-39.pyc -------------------------------------------------------------------------------- /payment/__pycache__/views.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/payment/__pycache__/views.cpython-39.pyc -------------------------------------------------------------------------------- /store/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/store/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /store/__pycache__/models.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/store/__pycache__/models.cpython-39.pyc -------------------------------------------------------------------------------- /account/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/account/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /basket/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/basket/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /orders/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/orders/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /payment/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/payment/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /store/context_processors.py: -------------------------------------------------------------------------------- 1 | from .models import Category 2 | 3 | 4 | def categories(request): 5 | return {"categories": Category.objects.filter(level=0)} 6 | -------------------------------------------------------------------------------- /templates/two_factor/twilio/sms_message.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% blocktrans trimmed %} 3 | Your OTP token is {{ token }} 4 | {% endblocktrans %} 5 | 6 | -------------------------------------------------------------------------------- /core/settings/__pycache__/base.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/core/settings/__pycache__/base.cpython-39.pyc -------------------------------------------------------------------------------- /core/settings/__pycache__/core.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/core/settings/__pycache__/core.cpython-39.pyc -------------------------------------------------------------------------------- /orders/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from .models import Order, OrderItem 4 | 5 | admin.site.register(Order) 6 | admin.site.register(OrderItem) -------------------------------------------------------------------------------- /store/tests/__pycache__/tests.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/store/tests/__pycache__/tests.cpython-39.pyc -------------------------------------------------------------------------------- /basket/tests/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/basket/tests/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /store/tests/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/store/tests/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /basket/tests/__pycache__/test_views.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/basket/tests/__pycache__/test_views.cpython-39.pyc -------------------------------------------------------------------------------- /core/settings/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/core/settings/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /core/settings/__pycache__/dev_debug.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/core/settings/__pycache__/dev_debug.cpython-39.pyc -------------------------------------------------------------------------------- /store/__pycache__/context_processors.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/store/__pycache__/context_processors.cpython-39.pyc -------------------------------------------------------------------------------- /store/tests/__pycache__/test_models.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/store/tests/__pycache__/test_models.cpython-39.pyc -------------------------------------------------------------------------------- /store/tests/__pycache__/test_views.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/store/tests/__pycache__/test_views.cpython-39.pyc -------------------------------------------------------------------------------- /basket/__pycache__/context_processors.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/basket/__pycache__/context_processors.cpython-39.pyc -------------------------------------------------------------------------------- /basket/migrations/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/basket/migrations/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /orders/migrations/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/orders/migrations/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /store/migrations/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/store/migrations/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /account/migrations/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/account/migrations/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /account/templatetags/__pycache__/example.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/account/templatetags/__pycache__/example.cpython-39.pyc -------------------------------------------------------------------------------- /payment/migrations/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/payment/migrations/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /store/migrations/__pycache__/0001_initial.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/store/migrations/__pycache__/0001_initial.cpython-39.pyc -------------------------------------------------------------------------------- /account/migrations/__pycache__/0001_initial.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/account/migrations/__pycache__/0001_initial.cpython-39.pyc -------------------------------------------------------------------------------- /orders/migrations/__pycache__/0001_initial.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/orders/migrations/__pycache__/0001_initial.cpython-39.pyc -------------------------------------------------------------------------------- /orders/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from . import views 4 | 5 | app_name = 'orders' 6 | 7 | urlpatterns = [ 8 | path('add/', views.add, name='add'), 9 | ] 10 | -------------------------------------------------------------------------------- /store/migrations/__pycache__/0002_product_is_active.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/store/migrations/__pycache__/0002_product_is_active.cpython-39.pyc -------------------------------------------------------------------------------- /store/migrations/__pycache__/0003_imagealbum_name.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/store/migrations/__pycache__/0003_imagealbum_name.cpython-39.pyc -------------------------------------------------------------------------------- /account/migrations/__pycache__/0002_userbase_is_staff.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/account/migrations/__pycache__/0002_userbase_is_staff.cpython-39.pyc -------------------------------------------------------------------------------- /orders/migrations/__pycache__/0002_remove_order_email.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/orders/migrations/__pycache__/0002_remove_order_email.cpython-39.pyc -------------------------------------------------------------------------------- /store/migrations/__pycache__/0002_auto_20201221_1612.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/store/migrations/__pycache__/0002_auto_20201221_1612.cpython-39.pyc -------------------------------------------------------------------------------- /store/migrations/__pycache__/0002_auto_20210130_0004.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/store/migrations/__pycache__/0002_auto_20210130_0004.cpython-39.pyc -------------------------------------------------------------------------------- /store/migrations/__pycache__/0003_auto_20201223_1409.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/store/migrations/__pycache__/0003_auto_20201223_1409.cpython-39.pyc -------------------------------------------------------------------------------- /store/migrations/__pycache__/0004_auto_20201224_0015.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/store/migrations/__pycache__/0004_auto_20201224_0015.cpython-39.pyc -------------------------------------------------------------------------------- /store/migrations/__pycache__/0004_auto_20210129_1731.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/veryacademy/YT_Django_Two_Factor_Example/HEAD/store/migrations/__pycache__/0004_auto_20210129_1731.cpython-39.pyc -------------------------------------------------------------------------------- /static/account/css/account.css: -------------------------------------------------------------------------------- 1 | .account-form input { 2 | border: 2px solid #ccc; 3 | height: calc(2em + .75rem + 2px); 4 | } 5 | 6 | .account-form input:focus { 7 | border-color: #1497ff; 8 | box-shadow: none; 9 | } -------------------------------------------------------------------------------- /templates/two_factor/_wizard_forms.html: -------------------------------------------------------------------------------- 1 | {% load example %} 2 | {{ wizard.management_form }} 3 | 4 | {% for field in wizard.form %} 5 | 6 | {{field | add_classes:'form-control mb-2 account-form'}} 7 | {% endfor %} 8 | -------------------------------------------------------------------------------- /templates/account/registration/account_activation_email.html: -------------------------------------------------------------------------------- 1 | {% autoescape off %} 2 | Hi {{ user.user_name }}, 3 | 4 | Your account has successfully created. Please click below link to activate your account 5 | 6 | http://{{ domain }}{% url 'account:activate' uidb64=uid token=token %} 7 | {% endautoescape %} -------------------------------------------------------------------------------- /templates/two_factor/_base_focus.html: -------------------------------------------------------------------------------- 1 | {% extends "two_factor/_base.html" %} 2 | 3 | {% block content_wrapper %} 4 |
Please contact our support team
9 |You have now deleted your account
9 |Check your email to activate your account
9 |{% blocktrans trimmed %}You are about to disable two-factor authentication. This 7 | weakens your account security, are you sure?{% endblocktrans %}
8 | 14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # YT_Django_Project_Ecommerce_v1_Part3 2 | 3 | ## Instructions 4 | 5 | 1. Download 6 | 2. Extract in a folder 7 | 3. Open with visual studio code 8 | 9 | Commands: 10 | 11 | py -m venv venv 12 | venv\Scripts\activate 13 | pip install -r requirements.txt 14 | py manage.py runserver 15 | 16 | 17 | In core /settings.py the stripe is commented out - just put your own details in here (not all of these are connected to the project) 18 | 19 | # Stripe Payment 20 | PUBLISHABLE_KEY = '' 21 | SECRET_KEY = '' 22 | 23 | # Admin login 24 | 1. http://127.0.0.1:8000/admin 25 | 2. username and password = admin -------------------------------------------------------------------------------- /templates/account/password_reset/reset_status.html: -------------------------------------------------------------------------------- 1 | {% extends "../sub_base.html" %} 2 | {% block title %}Reset Status{% endblock %} 3 | {% block content %} 4 | 5 |Check your email for instructions
10 | {% endif%} 11 | {% if 'complete' in request.get_full_path %} 12 |{% blocktrans trimmed %}The page you requested, enforces users to verify using 8 | two-factor authentication for security reasons. You need to enable these 9 | security features in order to access this page.{% endblocktrans %}
10 | 11 |{% blocktrans trimmed %}Two-factor authentication is not enabled for your 12 | account. Enable two-factor authentication for enhanced account 13 | security.{% endblocktrans %}
14 |15 | {% trans "Go back" %} 17 | 18 | {% trans "Enable Two-Factor Authentication" %} 19 |
20 | {% endblock %} 21 | -------------------------------------------------------------------------------- /store/admin.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from django.contrib import admin 3 | from mptt.admin import MPTTModelAdmin 4 | 5 | from .models import ( 6 | Category, 7 | Product, 8 | ProductImage, 9 | ProductSpecification, 10 | ProductSpecificationValue, 11 | ProductType, 12 | ) 13 | 14 | admin.site.register(Category, MPTTModelAdmin) 15 | 16 | 17 | class ProductSpecificationInline(admin.TabularInline): 18 | model = ProductSpecification 19 | 20 | 21 | @admin.register(ProductType) 22 | class ProductTypeAdmin(admin.ModelAdmin): 23 | inlines = [ 24 | ProductSpecificationInline, 25 | ] 26 | 27 | 28 | class ProductImageInline(admin.TabularInline): 29 | model = ProductImage 30 | 31 | 32 | class ProductSpecificationValueInline(admin.TabularInline): 33 | model = ProductSpecificationValue 34 | 35 | 36 | @admin.register(Product) 37 | class ProductAdmin(admin.ModelAdmin): 38 | inlines = [ 39 | ProductSpecificationValueInline, 40 | ProductImageInline, 41 | ] 42 | -------------------------------------------------------------------------------- /templates/two_factor/core/phone_register.html: -------------------------------------------------------------------------------- 1 | {% extends "two_factor/_base_focus.html" %} 2 | {% load i18n %} 3 | 4 | {% block content %} 5 |{% blocktrans trimmed %}You'll be adding a backup phone number to your 9 | account. This number will be used if your primary method of 10 | registration is not available.{% endblocktrans %}
11 | {% elif wizard.steps.current == 'validation' %} 12 |{% blocktrans trimmed %}We've sent a token to your phone number. Please 13 | enter the token you've received.{% endblocktrans %}
14 | {% endif %} 15 | 16 | 24 | {% endblock %} 25 | -------------------------------------------------------------------------------- /templates/account/password_reset/password_reset_form.html: -------------------------------------------------------------------------------- 1 | {% extends "../sub_base.html" %} 2 | {% block title %}Reset your account{% endblock %} 3 | {% block sub_content %} 4 | 5 | {% if request.user.is_authenticated %} 6 | 9 | {% endif %} 10 | 11 | 26 | 27 | {% endblock %} -------------------------------------------------------------------------------- /core/settings/dev_debug.py: -------------------------------------------------------------------------------- 1 | from .base import * 2 | 3 | # debug_toolbar settings 4 | if DEBUG: 5 | INTERNAL_IPS = ("127.0.0.1",) 6 | MIDDLEWARE += ("debug_toolbar.middleware.DebugToolbarMiddleware",) 7 | 8 | INSTALLED_APPS += ("debug_toolbar",) 9 | 10 | DEBUG_TOOLBAR_PANELS = [ 11 | "debug_toolbar.panels.versions.VersionsPanel", 12 | "debug_toolbar.panels.timer.TimerPanel", 13 | "debug_toolbar.panels.settings.SettingsPanel", 14 | "debug_toolbar.panels.headers.HeadersPanel", 15 | "debug_toolbar.panels.request.RequestPanel", 16 | "debug_toolbar.panels.sql.SQLPanel", 17 | "debug_toolbar.panels.staticfiles.StaticFilesPanel", 18 | "debug_toolbar.panels.templates.TemplatesPanel", 19 | "debug_toolbar.panels.cache.CachePanel", 20 | "debug_toolbar.panels.signals.SignalsPanel", 21 | "debug_toolbar.panels.logging.LoggingPanel", 22 | "debug_toolbar.panels.redirects.RedirectsPanel", 23 | ] 24 | 25 | DEBUG_TOOLBAR_CONFIG = { 26 | "INTERCEPT_REDIRECTS": False, 27 | } 28 | -------------------------------------------------------------------------------- /templates/two_factor/core/setup_complete.html: -------------------------------------------------------------------------------- 1 | {% extends "two_factor/_base_focus.html" %} 2 | {% load i18n %} 3 | 4 | {% block content %} 5 |{% blocktrans trimmed %}Congratulations, you've successfully enabled two-factor 8 | authentication.{% endblocktrans %}
9 | 10 | {% if not phone_methods %} 11 |{% trans "Back to Account Security" %}
13 | {% else %} 14 |{% blocktrans trimmed %}However, it might happen that you don't have access to 15 | your primary token device. To enable account recovery, add a phone 16 | number.{% endblocktrans %}
17 | 18 | {% trans "Back to Account Security" %} 20 |{% trans "Add Phone Number" %}
22 | {% endif %} 23 | 24 | {% endblock %} 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Very Academy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /templates/account/login.html: -------------------------------------------------------------------------------- 1 | {% extends "./sub_base.html" %} 2 | {% block title %}Log-in{% endblock %} 3 | {% block sub_content %} 4 | 5 | 27 | 28 | {% endblock %} -------------------------------------------------------------------------------- /_documentation/database_schema.txt: -------------------------------------------------------------------------------- 1 | https://dbdiagram.io/d 2 | 3 | 4 | Table category as C { 5 | id int [pk, increment] 6 | name varchar 7 | slug slug 8 | parent varchar 9 | is_active boolean 10 | } 11 | 12 | Table ProductType as PT { 13 | id int [pk, increment] 14 | name varchar 15 | is_active boolean 16 | } 17 | 18 | Table ProductSpecification as PS { 19 | id int [pk, increment] 20 | product_type int 21 | name varchar 22 | } 23 | Ref: PT.id < PS.product_type 24 | 25 | Table Product as P { 26 | id int [pk, increment] 27 | product_type int 28 | category int 29 | description varchar 30 | slug slug 31 | regular_price decimal 32 | discount_price decimal 33 | is_active boolean 34 | created_at timestamp 35 | updated_at timestamp 36 | } 37 | Ref: PT.id < P.product_type 38 | Ref: C.id < P.category 39 | 40 | Table ProductSpecificationValue as PSV { 41 | id int [pk, increment] 42 | product int 43 | specification int 44 | value varchar 45 | } 46 | Ref: P.id < PSV.product 47 | Ref: PS.id < PSV.specification 48 | 49 | Table ProductImage as PI { 50 | id int [pk, increment] 51 | product int 52 | image image 53 | is_feature boolean 54 | created_at timestamp 55 | updated_at timestamp 56 | } 57 | Ref: P.id < PI.product -------------------------------------------------------------------------------- /templates/two_factor/core/backup_tokens.html: -------------------------------------------------------------------------------- 1 | {% extends "../_base.html" %} 2 | {% load i18n %} 3 | 4 | {% block sub_content %} 5 |{% blocktrans trimmed %}Backup tokens can be used when your primary and backup 7 | phone numbers aren't available. The backup tokens below can be used 8 | for login verification. If you've used up all your backup tokens, you 9 | can generate a new set of backup tokens. Only the backup tokens shown 10 | below will be valid.{% endblocktrans %}
11 | 12 | {% if device.token_set.count %} 13 |{% blocktrans %}Print these tokens and keep them somewhere safe.{% endblocktrans %}
19 | {% else %} 20 |{% trans "You don't have any backup codes yet." %}
21 | {% endif %} 22 | 23 | 28 | {% endblock %} 29 | -------------------------------------------------------------------------------- /orders/views.py: -------------------------------------------------------------------------------- 1 | from django.http.response import JsonResponse 2 | from django.shortcuts import render 3 | 4 | from basket.basket import Basket 5 | 6 | from .models import Order, OrderItem 7 | 8 | 9 | def add(request): 10 | basket = Basket(request) 11 | if request.POST.get('action') == 'post': 12 | 13 | order_key = request.POST.get('order_key') 14 | user_id = request.user.id 15 | baskettotal = basket.get_total_price() 16 | 17 | # Check if order exists 18 | if Order.objects.filter(order_key=order_key).exists(): 19 | pass 20 | else: 21 | order = Order.objects.create(user_id=user_id, full_name='name', address1='add1', 22 | address2='add2', total_paid=baskettotal, order_key=order_key) 23 | order_id = order.pk 24 | 25 | for item in basket: 26 | OrderItem.objects.create(order_id=order_id, product=item['product'], price=item['price'], quantity=item['qty']) 27 | 28 | response = JsonResponse({'success': 'Return something'}) 29 | return response 30 | 31 | 32 | def payment_confirmation(data): 33 | Order.objects.filter(order_key=data).update(billing_status=True) 34 | 35 | 36 | def user_orders(request): 37 | user_id = request.user.id 38 | orders = Order.objects.filter(user_id=user_id).filter(billing_status=True) 39 | return orders 40 | -------------------------------------------------------------------------------- /templates/account/password_reset/password_reset_confirm.html: -------------------------------------------------------------------------------- 1 | {% extends "../sub_base.html" %} 2 | {% block title %}Password Reset Confirm{% endblock %} 3 | {% block sub_content %} 4 | 5 | {% if request.user.is_authenticated %} 6 | 9 | {% endif %} 10 | 11 | 35 | 36 | {% endblock %} -------------------------------------------------------------------------------- /templates/account/registration/register.html: -------------------------------------------------------------------------------- 1 | {% extends "../sub_base.html" %} 2 | {% block title %}Register Account{% endblock %} 3 | {% block sub_content %} 4 | 5 | 41 | 42 | {% endblock %} -------------------------------------------------------------------------------- /orders/models.py: -------------------------------------------------------------------------------- 1 | from decimal import Decimal 2 | from django.conf import settings 3 | from django.db import models 4 | 5 | from store.models import Product 6 | 7 | 8 | class Order(models.Model): 9 | user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='order_user') 10 | full_name = models.CharField(max_length=50) 11 | address1 = models.CharField(max_length=250) 12 | address2 = models.CharField(max_length=250) 13 | city = models.CharField(max_length=100) 14 | phone = models.CharField(max_length=100) 15 | post_code = models.CharField(max_length=20) 16 | created = models.DateTimeField(auto_now_add=True) 17 | updated = models.DateTimeField(auto_now=True) 18 | total_paid = models.DecimalField(max_digits=5, decimal_places=2) 19 | order_key = models.CharField(max_length=200) 20 | billing_status = models.BooleanField(default=False) 21 | 22 | class Meta: 23 | ordering = ('-created',) 24 | 25 | def __str__(self): 26 | return str(self.created) 27 | 28 | 29 | class OrderItem(models.Model): 30 | order = models.ForeignKey(Order, 31 | related_name='items', 32 | on_delete=models.CASCADE) 33 | product = models.ForeignKey(Product, 34 | related_name='order_items', 35 | on_delete=models.CASCADE) 36 | price = models.DecimalField(max_digits=5, decimal_places=2) 37 | quantity = models.PositiveIntegerField(default=1) 38 | 39 | def __str__(self): 40 | return str(self.id) 41 | -------------------------------------------------------------------------------- /templates/account/dashboard/edit_addresses.html: -------------------------------------------------------------------------------- 1 | {% extends "../sub_base.html" %} 2 | {% block title %}Edit Addresses{% endblock %} 3 | 4 | {% block sub_content %} 5 |33 | {{ product.title }} 34 |
35 |37 | {{ product.title|slice:":50" }}... 39 |
40 |{% blocktrans %}Enter your credentials.{% endblocktrans %}
10 | {% elif wizard.steps.current == 'token' %} 11 | {% if device.method == 'call' %} 12 |{% blocktrans trimmed %}We are calling your phone right now, please enter the 13 | digits you hear.{% endblocktrans %}
14 | {% elif device.method == 'sms' %} 15 |{% blocktrans trimmed %}We sent you a text message, please enter the tokens we 16 | sent.{% endblocktrans %}
17 | {% else %} 18 |{% blocktrans trimmed %}Please enter the tokens generated by your token 19 | generator.{% endblocktrans %}
20 | {% endif %} 21 | {% elif wizard.steps.current == 'backup' %} 22 |{% blocktrans trimmed %}Use this form for entering backup tokens for logging in. 23 | These tokens have been generated for you to print and keep safe. Please 24 | enter one of these backup tokens to login to your account.{% endblocktrans %}
25 | {% endif %} 26 | 27 | 53 |{{address.full_name}}
42 |{{address.address_line}}
43 |{{address.address_line2}}
44 |{{address.town_city}}
45 |{{address.postcode}}
46 |Phone number: {{address.phone}}
47 |includes tax
16 |{% blocktrans trimmed %}You are about to take your account security to the 8 | next level. Follow the steps in this wizard to enable two-factor 9 | authentication.{% endblocktrans %}
10 | {% elif wizard.steps.current == 'method' %} 11 |{% blocktrans trimmed %}Please select which authentication method you would 12 | like to use.{% endblocktrans %}
13 | {% elif wizard.steps.current == 'generator' %} 14 |{% blocktrans trimmed %}To start using a token generator, please use your 15 | smartphone to scan the QR code below. For example, use Google 16 | Authenticator. Then, enter the token generated by the app. 17 | {% endblocktrans %}
18 |{% blocktrans trimmed %}Please enter the phone number you wish to receive the 21 | text messages on. This number will be validated in the next step. 22 | {% endblocktrans %}
23 | {% elif wizard.steps.current == 'call' %} 24 |{% blocktrans trimmed %}Please enter the phone number you wish to be called on. 25 | This number will be validated in the next step. {% endblocktrans %}
26 | {% elif wizard.steps.current == 'validation' %} 27 | {% if challenge_succeeded %} 28 | {% if device.method == 'call' %} 29 |{% blocktrans trimmed %}We are calling your phone right now, please enter the 30 | digits you hear.{% endblocktrans %}
31 | {% elif device.method == 'sms' %} 32 |{% blocktrans trimmed %}We sent you a text message, please enter the tokens we 33 | sent.{% endblocktrans %}
34 | {% endif %} 35 | {% else %} 36 |{% blocktrans trimmed %}We've 37 | encountered an issue with the selected authentication method. Please 38 | go back and verify that you entered your information correctly, try 39 | again, or use a different authentication method instead. If the issue 40 | persists, contact the site administrator.{% endblocktrans %}
41 | {% endif %} 42 | {% elif wizard.steps.current == 'yubikey' %} 43 |{% blocktrans trimmed %}To identify and verify your YubiKey, please insert a 44 | token in the field below. Your YubiKey will be linked to your 45 | account.{% endblocktrans %}
46 | {% endif %} 47 | 48 | 56 | {% endblock %} 57 | -------------------------------------------------------------------------------- /templates/two_factor/profile/profile.html: -------------------------------------------------------------------------------- 1 | {% extends "../_base.html" %} 2 | {% load i18n two_factor %} 3 | 4 | {% block sub_content %} 5 |{% trans "Tokens will be generated by your token generator." %}
10 | {% elif default_device_type == 'PhoneDevice' %} 11 |{% blocktrans with primary=default_device|device_action %}Primary method: {{ primary }}{% endblocktrans %}
12 | {% elif default_device_type == 'RemoteYubikeyDevice' %} 13 |{% blocktrans %}Tokens will be generated by your YubiKey.{% endblocktrans %}
14 | {% endif %} 15 | 16 | {% if available_phone_methods %} 17 |{% blocktrans trimmed %}If your primary method is not available, we are able to 19 | send backup tokens to the phone numbers listed below.{% endblocktrans %}
20 |{% trans "Add Phone Number" %}
35 | {% endif %} 36 | 37 |39 | {% blocktrans trimmed %}If you don't have any device with you, you can access 40 | your account using backup tokens.{% endblocktrans %} 41 | {% blocktrans trimmed count counter=backup_tokens %} 42 | You have only one backup token remaining. 43 | {% plural %} 44 | You have {{ counter }} backup tokens remaining. 45 | {% endblocktrans %} 46 |
47 | 49 | 50 |{% blocktrans trimmed %}However we strongly discourage you to do so, you can 52 | also disable two-factor authentication for your account.{% endblocktrans %}
53 |54 | {% trans "Disable Two-Factor Authentication" %}
55 | {% else %} 56 |{% blocktrans trimmed %}Two-factor authentication is not enabled for your 57 | account. Enable two-factor authentication for enhanced account 58 | security.{% endblocktrans %}
59 |60 | {% trans "Enable Two-Factor Authentication" %} 61 |
62 | {% endif %} 63 | {% endblock %} 64 | -------------------------------------------------------------------------------- /templates/payment/payment_form.html: -------------------------------------------------------------------------------- 1 | {% extends "./sub_base.html" %} 2 | {% load static %} 3 | {% block title %}Make Payment{% endblock %} 4 | 5 | {% block sub_content %} 6 | 7 | 74 | 75 | 79 | 80 | 81 | 82 | {% endblock %} -------------------------------------------------------------------------------- /account/models.py: -------------------------------------------------------------------------------- 1 | import uuid 2 | 3 | from django.contrib.auth.models import (AbstractBaseUser, BaseUserManager, 4 | PermissionsMixin) 5 | from django.core.mail import send_mail 6 | from django.db import models 7 | from django.utils.translation import gettext_lazy as _ 8 | 9 | 10 | class CustomAccountManager(BaseUserManager): 11 | 12 | def create_superuser(self, email, name, password, **other_fields): 13 | 14 | other_fields.setdefault('is_staff', True) 15 | other_fields.setdefault('is_superuser', True) 16 | other_fields.setdefault('is_active', True) 17 | 18 | if other_fields.get('is_staff') is not True: 19 | raise ValueError( 20 | 'Superuser must be assigned to is_staff=True.') 21 | if other_fields.get('is_superuser') is not True: 22 | raise ValueError( 23 | 'Superuser must be assigned to is_superuser=True.') 24 | 25 | return self.create_user(email, name, password, **other_fields) 26 | 27 | def create_user(self, email, name, password, **other_fields): 28 | 29 | if not email: 30 | raise ValueError(_('You must provide an email address')) 31 | 32 | email = self.normalize_email(email) 33 | user = self.model(email=email, name=name, 34 | **other_fields) 35 | user.set_password(password) 36 | user.save() 37 | return user 38 | 39 | 40 | class Customer(AbstractBaseUser, PermissionsMixin): 41 | email = models.EmailField(_('email address'), unique=True) 42 | name = models.CharField(max_length=150) 43 | mobile = models.CharField(max_length=20, blank=True) 44 | is_active = models.BooleanField(default=False) 45 | is_staff = models.BooleanField(default=False) 46 | created = models.DateTimeField(auto_now_add=True) 47 | updated = models.DateTimeField(auto_now=True) 48 | 49 | objects = CustomAccountManager() 50 | 51 | USERNAME_FIELD = 'email' 52 | REQUIRED_FIELDS = ['name'] 53 | 54 | class Meta: 55 | verbose_name = "Accounts" 56 | verbose_name_plural = "Accounts" 57 | 58 | def email_user(self, subject, message): 59 | send_mail( 60 | subject, 61 | message, 62 | 'l@1.com', 63 | [self.email], 64 | fail_silently=False, 65 | ) 66 | 67 | def __str__(self): 68 | return self.name 69 | 70 | class Address(models.Model): 71 | """ 72 | Address 73 | """ 74 | 75 | id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) 76 | customer = models.ForeignKey(Customer, verbose_name=_("Customer"), on_delete=models.CASCADE) 77 | full_name = models.CharField(_("Full Name"), max_length=150) 78 | phone = models.CharField(_("Phone Number"), max_length=50) 79 | postcode = models.CharField(_("Postcode"), max_length=50) 80 | address_line = models.CharField(_("Address Line 1"), max_length=255) 81 | address_line2 = models.CharField(_("Address Line 2"), max_length=255) 82 | town_city = models.CharField(_("Town/City/State"), max_length=150) 83 | delivery_instructions = models.CharField(_("Delivery Instructions"), max_length=255) 84 | created_at = models.DateTimeField(_("Created at"), auto_now_add=True) 85 | updated_at = models.DateTimeField(_("Updated at"), auto_now=True) 86 | default = models.BooleanField(_("Default"), default=False) 87 | 88 | class Meta: 89 | verbose_name = "Address" 90 | verbose_name_plural = "Addresses" 91 | 92 | def __str__(self): 93 | return "Address" -------------------------------------------------------------------------------- /account/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.7 on 2021-03-02 14:12 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | import uuid 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | initial = True 12 | 13 | dependencies = [ 14 | ('auth', '0012_alter_user_first_name_max_length'), 15 | ] 16 | 17 | operations = [ 18 | migrations.CreateModel( 19 | name='Customer', 20 | fields=[ 21 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 22 | ('password', models.CharField(max_length=128, verbose_name='password')), 23 | ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), 24 | ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), 25 | ('email', models.EmailField(max_length=254, unique=True, verbose_name='email address')), 26 | ('name', models.CharField(max_length=150)), 27 | ('mobile', models.CharField(blank=True, max_length=20)), 28 | ('is_active', models.BooleanField(default=False)), 29 | ('is_staff', models.BooleanField(default=False)), 30 | ('created', models.DateTimeField(auto_now_add=True)), 31 | ('updated', models.DateTimeField(auto_now=True)), 32 | ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')), 33 | ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), 34 | ], 35 | options={ 36 | 'verbose_name': 'Accounts', 37 | 'verbose_name_plural': 'Accounts', 38 | }, 39 | ), 40 | migrations.CreateModel( 41 | name='Address', 42 | fields=[ 43 | ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), 44 | ('full_name', models.CharField(max_length=150, verbose_name='Full Name')), 45 | ('phone', models.CharField(max_length=50, verbose_name='Phone Number')), 46 | ('postcode', models.CharField(max_length=50, verbose_name='Postcode')), 47 | ('address_line', models.CharField(max_length=255, verbose_name='Address Line 1')), 48 | ('address_line2', models.CharField(max_length=255, verbose_name='Address Line 2')), 49 | ('town_city', models.CharField(max_length=150, verbose_name='Town/City/State')), 50 | ('delivery_instructions', models.CharField(max_length=255, verbose_name='Delivery Instructions')), 51 | ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')), 52 | ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')), 53 | ('default', models.BooleanField(default=False, verbose_name='Default')), 54 | ('customer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Customer')), 55 | ], 56 | options={ 57 | 'verbose_name': 'Address', 58 | 'verbose_name_plural': 'Addresses', 59 | }, 60 | ), 61 | ] 62 | -------------------------------------------------------------------------------- /core/settings/base.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pathlib import Path 3 | 4 | BASE_DIR = Path(__file__).resolve().parent.parent.parent 5 | 6 | SECRET_KEY = "3xk*)i0x#k$btl=(6q)te!19=mp6d)lm1+zl#ts4ewxi3-!vm_" 7 | 8 | DEBUG = True 9 | 10 | ALLOWED_HOSTS = ["yourdomain.com", "127.0.0.1", "localhost"] 11 | 12 | INSTALLED_APPS = [ 13 | "django.contrib.admin", 14 | "django.contrib.auth", 15 | "django.contrib.contenttypes", 16 | "django.contrib.sessions", 17 | "django.contrib.messages", 18 | "django.contrib.staticfiles", 19 | "store", 20 | "basket", 21 | "account", 22 | "orders", 23 | "mptt", 24 | "core", 25 | # 2FA 26 | "django_otp", 27 | "django_otp.plugins.otp_static", 28 | "django_otp.plugins.otp_totp", 29 | "two_factor", 30 | ] 31 | 32 | MIDDLEWARE = [ 33 | "django.middleware.security.SecurityMiddleware", 34 | "django.contrib.sessions.middleware.SessionMiddleware", 35 | "django.middleware.common.CommonMiddleware", 36 | "django.middleware.csrf.CsrfViewMiddleware", 37 | "django.contrib.auth.middleware.AuthenticationMiddleware", 38 | "django_otp.middleware.OTPMiddleware", 39 | "django.contrib.messages.middleware.MessageMiddleware", 40 | "django.middleware.clickjacking.XFrameOptionsMiddleware", 41 | ] 42 | 43 | ROOT_URLCONF = "core.urls" 44 | 45 | TEMPLATES = [ 46 | { 47 | "BACKEND": "django.template.backends.django.DjangoTemplates", 48 | "DIRS": [BASE_DIR / "templates"], 49 | "APP_DIRS": True, 50 | "OPTIONS": { 51 | "context_processors": [ 52 | "django.template.context_processors.debug", 53 | "django.template.context_processors.request", 54 | "django.contrib.auth.context_processors.auth", 55 | "django.contrib.messages.context_processors.messages", 56 | "store.context_processors.categories", 57 | "basket.context_processors.basket", 58 | ], 59 | }, 60 | }, 61 | ] 62 | 63 | WSGI_APPLICATION = "core.wsgi.application" 64 | 65 | DATABASES = { 66 | "default": { 67 | "ENGINE": "django.db.backends.sqlite3", 68 | "NAME": BASE_DIR / "db.sqlite3", 69 | } 70 | } 71 | 72 | AUTH_PASSWORD_VALIDATORS = [ 73 | { 74 | "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", 75 | }, 76 | { 77 | "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", 78 | }, 79 | { 80 | "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", 81 | }, 82 | { 83 | "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", 84 | }, 85 | ] 86 | 87 | LANGUAGE_CODE = "en-us" 88 | 89 | TIME_ZONE = "UTC" 90 | 91 | USE_I18N = True 92 | 93 | USE_L10N = True 94 | 95 | USE_TZ = True 96 | 97 | STATIC_URL = "/static/" 98 | 99 | STATICFILES_DIRS = [os.path.join(BASE_DIR, "static")] 100 | 101 | MEDIA_URL = "/media/" 102 | MEDIA_ROOT = os.path.join(BASE_DIR, "media/") 103 | 104 | # Basket session ID 105 | BASKET_SESSION_ID = "basket" 106 | 107 | # Stripe Payment 108 | os.environ.setdefault( 109 | "STRIPE_PUBLISHABLE_KEY", 110 | "pk_test_51IHxTTJm9Ogh6om63DrCDlFfxcPDTvbUVy1CoSiI1ZS2GKt8UJojUJlbo9CAOCHnNgEqwKlQlnv9TmyzKIUUkr8800w8nNvBfw", 111 | ) 112 | STRIPE_SECRET_KEY = ( 113 | "sk_test_51IHxTTJm9Ogh6om6ryBhjePFWUTXvweI5y5gXjFhgPWVztF83X6Rhae1LGfW8bteV5ebb2KhX9w61Q1117Sw1iHE00gzR7PmNq" 114 | ) 115 | # stripe listen --forward-to localhost:8000/payment/webhook/ 116 | 117 | # Custom user model 118 | AUTH_USER_MODEL = "account.Customer" 119 | LOGIN_REDIRECT_URL = "/account/dashboard" 120 | # LOGIN_URL = "/account/login/" 121 | LOGIN_URL = "two_factor:login" 122 | 123 | # Email setting 124 | EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" 125 | -------------------------------------------------------------------------------- /basket/basket.py: -------------------------------------------------------------------------------- 1 | from decimal import Decimal 2 | 3 | from django.conf import settings 4 | from store.models import Product 5 | 6 | 7 | class Basket: 8 | """ 9 | A base Basket class, providing some default behaviors that 10 | can be inherited or overrided, as necessary. 11 | """ 12 | 13 | def __init__(self, request): 14 | self.session = request.session 15 | basket = self.session.get(settings.BASKET_SESSION_ID) 16 | if settings.BASKET_SESSION_ID not in request.session: 17 | basket = self.session[settings.BASKET_SESSION_ID] = {} 18 | self.basket = basket 19 | 20 | def add(self, product, qty): 21 | """ 22 | Adding and updating the users basket session data 23 | """ 24 | product_id = str(product.id) 25 | 26 | if product_id in self.basket: 27 | self.basket[product_id]["qty"] = qty 28 | else: 29 | self.basket[product_id] = {"price": str(product.regular_price), "qty": qty} 30 | 31 | self.save() 32 | 33 | def __iter__(self): 34 | """ 35 | Collect the product_id in the session data to query the database 36 | and return products 37 | """ 38 | product_ids = self.basket.keys() 39 | products = Product.objects.filter(id__in=product_ids) 40 | basket = self.basket.copy() 41 | 42 | for product in products: 43 | basket[str(product.id)]["product"] = product 44 | 45 | for item in basket.values(): 46 | item["price"] = Decimal(item["price"]) 47 | item["total_price"] = item["price"] * item["qty"] 48 | yield item 49 | 50 | def __len__(self): 51 | """ 52 | Get the basket data and count the qty of items 53 | """ 54 | return sum(item["qty"] for item in self.basket.values()) 55 | 56 | def update(self, product, qty): 57 | """ 58 | Update values in session data 59 | """ 60 | product_id = str(product) 61 | if product_id in self.basket: 62 | self.basket[product_id]["qty"] = qty 63 | self.save() 64 | 65 | def get_subtotal_price(self): 66 | return sum(Decimal(item["price"]) * item["qty"] for item in self.basket.values()) 67 | 68 | def get_total_price(self): 69 | 70 | subtotal = sum(Decimal(item["price"]) * item["qty"] for item in self.basket.values()) 71 | 72 | if subtotal == 0: 73 | shipping = Decimal(0.00) 74 | else: 75 | shipping = Decimal(11.50) 76 | 77 | total = subtotal + Decimal(shipping) 78 | return total 79 | 80 | def delete(self, product): 81 | """ 82 | Delete item from session data 83 | """ 84 | product_id = str(product) 85 | 86 | if product_id in self.basket: 87 | del self.basket[product_id] 88 | self.save() 89 | 90 | def clear(self): 91 | # Remove basket from session 92 | del self.session[settings.BASKET_SESSION_ID] 93 | self.save() 94 | 95 | def save(self): 96 | self.session.modified = True 97 | 98 | 99 | """ 100 | Code in this file has been inspried/reworked from other known works. Plese ensure that 101 | the License below is included in any of your work that is directly copied from 102 | this source file. 103 | 104 | 105 | MIT License 106 | 107 | Copyright (c) 2019 Packt 108 | 109 | Permission is hereby granted, free of charge, to any person obtaining a copy 110 | of this software and associated documentation files (the "Software"), to deal 111 | in the Software without restriction, including without limitation the rights 112 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 113 | copies of the Software, and to permit persons to whom the Software is 114 | furnished to do so, subject to the following conditions: 115 | 116 | The above copyright notice and this permission notice shall be included in all 117 | copies or substantial portions of the Software. 118 | 119 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 120 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 121 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 122 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 123 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 124 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 125 | SOFTWARE. 126 | """ 127 | -------------------------------------------------------------------------------- /templates/account/dashboard/dashboard.html: -------------------------------------------------------------------------------- 1 | {% extends "../sub_base.html" %} 2 | {% block title %}Dashboard{% endblock %} 3 | 4 | {% block sub_content %} 5 | 6 |Manage your items in your basket
12 |