master 80e38cb5319c cached
267 files
841.2 KB
245.0k tokens
490 symbols
1 requests
Download .txt
Showing preview only (912K chars total). Download the full file or copy to clipboard to get everything.
Repository: codingforentrepreneurs/ecommerce
Branch: master
Commit: 80e38cb5319c
Files: 267
Total size: 841.2 KB

Directory structure:
gitextract_e8nnqks8/

├── .gitignore
├── README.md
├── ecommerce.code-workspace
├── ecommerce.sublime-project
├── ecommerce.sublime-workspace
├── fasttracktojquery/
│   └── index.html
├── notes/
│   └── checkout_process.md
├── parse_git_log.py
├── pyvenv.cfg
├── src/
│   ├── .gitignore
│   ├── Procfile
│   ├── accounts/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── forms.py
│   │   ├── migrations/
│   │   │   ├── 0001_initial.py
│   │   │   ├── 0002_user_full_name.py
│   │   │   ├── 0003_user_is_active.py
│   │   │   ├── 0004_remove_user_active.py
│   │   │   ├── 0005_emailactivation.py
│   │   │   └── __init__.py
│   │   ├── models.py
│   │   ├── passwords/
│   │   │   ├── __init__.py
│   │   │   └── urls.py
│   │   ├── signals.py
│   │   ├── templates/
│   │   │   └── accounts/
│   │   │       ├── detail-update-view.html
│   │   │       ├── home.html
│   │   │       ├── login.html
│   │   │       ├── register.html
│   │   │       └── snippets/
│   │   │           └── form.html
│   │   ├── tests.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── addresses/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── forms.py
│   │   ├── migrations/
│   │   │   ├── 0001_initial.py
│   │   │   ├── 0002_auto_20171107_0055.py
│   │   │   └── __init__.py
│   │   ├── models.py
│   │   ├── templates/
│   │   │   └── addresses/
│   │   │       ├── form.html
│   │   │       ├── list.html
│   │   │       ├── prev_addresses.html
│   │   │       └── update.html
│   │   ├── tests.py
│   │   └── views.py
│   ├── analytics/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── migrations/
│   │   │   ├── 0001_initial.py
│   │   │   ├── 0002_usersession.py
│   │   │   └── __init__.py
│   │   ├── mixins.py
│   │   ├── models.py
│   │   ├── signals.py
│   │   ├── templates/
│   │   │   └── analytics/
│   │   │       └── sales.html
│   │   ├── tests.py
│   │   ├── utils.py
│   │   └── views.py
│   ├── billing/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── migrations/
│   │   │   ├── 0001_initial.py
│   │   │   ├── 0002_auto_20170928_2052.py
│   │   │   ├── 0003_billingprofile_customer_id.py
│   │   │   ├── 0004_card.py
│   │   │   ├── 0005_card_default.py
│   │   │   ├── 0006_charge.py
│   │   │   ├── 0007_auto_20171012_1935.py
│   │   │   └── __init__.py
│   │   ├── models.py
│   │   ├── templates/
│   │   │   └── billing/
│   │   │       └── payment-method.html
│   │   ├── tests.py
│   │   └── views.py
│   ├── carts/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── migrations/
│   │   │   ├── 0001_initial.py
│   │   │   ├── 0002_cart_subtotal.py
│   │   │   └── __init__.py
│   │   ├── models.py
│   │   ├── templates/
│   │   │   └── carts/
│   │   │       ├── checkout-done.html
│   │   │       ├── checkout.html
│   │   │       ├── home.html
│   │   │       └── snippets/
│   │   │           └── remove-product.html
│   │   ├── tests.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── db.sqlite3
│   ├── db2.sqlite3
│   ├── ecommerce/
│   │   ├── __init__.py
│   │   ├── aws/
│   │   │   ├── __init__.py
│   │   │   ├── conf.py
│   │   │   ├── download/
│   │   │   │   ├── __init__.py
│   │   │   │   └── utils.py
│   │   │   └── utils.py
│   │   ├── forms.py
│   │   ├── mixins.py
│   │   ├── settings/
│   │   │   ├── __init__.py
│   │   │   ├── base.py
│   │   │   ├── local.py
│   │   │   └── production.py
│   │   ├── urls.py
│   │   ├── utils.py
│   │   ├── views.py
│   │   └── wsgi.py
│   ├── manage.py
│   ├── marketing/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── forms.py
│   │   ├── migrations/
│   │   │   ├── 0001_initial.py
│   │   │   ├── 0002_marketingpreference_mailchimp_subscribed.py
│   │   │   ├── 0003_auto_20171018_0142.py
│   │   │   └── __init__.py
│   │   ├── mixins.py
│   │   ├── models.py
│   │   ├── tests.py
│   │   ├── utils.py
│   │   └── views.py
│   ├── orders/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── migrations/
│   │   │   ├── 0001_initial.py
│   │   │   ├── 0002_auto_20170928_2224.py
│   │   │   ├── 0003_auto_20170929_0013.py
│   │   │   ├── 0004_auto_20171025_2216.py
│   │   │   ├── 0005_auto_20171107_0035.py
│   │   │   ├── 0006_productpurchase_productpurchasemanager.py
│   │   │   ├── 0007_auto_20171108_0028.py
│   │   │   ├── 0008_delete_productpurchasemanager.py
│   │   │   └── __init__.py
│   │   ├── models.py
│   │   ├── templates/
│   │   │   └── orders/
│   │   │       ├── library.html
│   │   │       ├── order_detail.html
│   │   │       └── order_list.html
│   │   ├── tests.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── products/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── fixtures/
│   │   │   └── products.json
│   │   ├── migrations/
│   │   │   ├── 0001_initial.py
│   │   │   ├── 0002_product_price.py
│   │   │   ├── 0003_product_image.py
│   │   │   ├── 0004_auto_20170901_2159.py
│   │   │   ├── 0005_product_featured.py
│   │   │   ├── 0006_auto_20170901_2254.py
│   │   │   ├── 0007_auto_20170901_2254.py
│   │   │   ├── 0008_auto_20170901_2300.py
│   │   │   ├── 0009_product_timestamp.py
│   │   │   ├── 0010_product_is_digital.py
│   │   │   ├── 0011_productfile.py
│   │   │   ├── 0012_auto_20171108_2325.py
│   │   │   ├── 0013_auto_20171109_0023.py
│   │   │   ├── 0014_auto_20171116_0011.py
│   │   │   ├── 0015_productfile_name.py
│   │   │   └── __init__.py
│   │   ├── models.py
│   │   ├── templates/
│   │   │   └── products/
│   │   │       ├── detail.html
│   │   │       ├── featured-detail.html
│   │   │       ├── list.html
│   │   │       ├── snippets/
│   │   │       │   ├── card.html
│   │   │       │   └── update-cart.html
│   │   │       └── user-history.html
│   │   ├── tests.py
│   │   ├── understanding_crud.md
│   │   ├── urls.py
│   │   └── views.py
│   ├── requirements.txt
│   ├── runtime.txt
│   ├── search/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── migrations/
│   │   │   └── __init__.py
│   │   ├── models.py
│   │   ├── templates/
│   │   │   └── search/
│   │   │       ├── snippets/
│   │   │       │   └── search-form.html
│   │   │       └── view.html
│   │   ├── tests.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── static_my_proj/
│   │   ├── css/
│   │   │   ├── main.css
│   │   │   └── stripe-custom-style.css
│   │   └── js/
│   │       ├── csrf.ajax.js
│   │       ├── ecommerce.js
│   │       ├── ecommerce.main.js
│   │       └── ecommerce.sales.js
│   ├── tags/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── migrations/
│   │   │   ├── 0001_initial.py
│   │   │   └── __init__.py
│   │   ├── models.py
│   │   ├── shell_commands.py
│   │   ├── tests.py
│   │   └── views.py
│   └── templates/
│       ├── 400.html
│       ├── 403.html
│       ├── 404.html
│       ├── 500.html
│       ├── base/
│       │   ├── css.html
│       │   ├── forms.html
│       │   ├── js.html
│       │   ├── js_templates.html
│       │   └── navbar.html
│       ├── base.html
│       ├── bootstrap/
│       │   └── example.html
│       ├── contact/
│       │   └── view.html
│       ├── home_page.html
│       └── registration/
│           ├── activation-error.html
│           ├── emails/
│           │   ├── verify.html
│           │   └── verify.txt
│           ├── password_change_done.html
│           ├── password_change_form.html
│           ├── password_reset_complete.html
│           ├── password_reset_confirm.html
│           ├── password_reset_done.html
│           ├── password_reset_email.html
│           ├── password_reset_email.txt
│           └── password_reset_form.html
└── static_cdn/
    ├── media_root/
    │   └── products/
    │       └── 2473283945/
    │           └── 2473283945.sublime-project
    ├── protected_media/
    │   └── product/
    │       └── my-awesome-album/
    │           ├── basic_audio.m4a
    │           ├── basic_audio_5W1qjNh.m4a
    │           ├── basic_audio_5W1qjNh_Ntvw9l5.m4a
    │           ├── basic_audio_DwLL00o.m4a
    │           ├── basic_audio_uuyWQIO.m4a
    │           └── basic_audio_uuyWQIO_soaLtH9.m4a
    └── static_root/
        ├── admin/
        │   ├── css/
        │   │   ├── base.css
        │   │   ├── changelists.css
        │   │   ├── dashboard.css
        │   │   ├── fonts.css
        │   │   ├── forms.css
        │   │   ├── login.css
        │   │   ├── rtl.css
        │   │   └── widgets.css
        │   ├── fonts/
        │   │   ├── LICENSE.txt
        │   │   └── README.txt
        │   ├── img/
        │   │   ├── LICENSE
        │   │   └── README.txt
        │   └── js/
        │       ├── SelectBox.js
        │       ├── SelectFilter2.js
        │       ├── actions.js
        │       ├── admin/
        │       │   ├── DateTimeShortcuts.js
        │       │   └── RelatedObjectLookups.js
        │       ├── calendar.js
        │       ├── cancel.js
        │       ├── change_form.js
        │       ├── collapse.js
        │       ├── core.js
        │       ├── inlines.js
        │       ├── jquery.init.js
        │       ├── popup_response.js
        │       ├── prepopulate.js
        │       ├── prepopulate_init.js
        │       ├── timeparse.js
        │       ├── urlify.js
        │       └── vendor/
        │           ├── jquery/
        │           │   ├── LICENSE-JQUERY.txt
        │           │   └── jquery.js
        │           └── xregexp/
        │               ├── LICENSE-XREGEXP.txt
        │               └── xregexp.js
        ├── css/
        │   ├── main.css
        │   └── stripe-custom-style.css
        └── js/
            ├── csrf.ajax.js
            ├── ecommerce.js
            └── ecommerce.main.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
.DS_STORE

.env
notes/email-activation.py
src/ecommerce/aws/ignore2.py

# Virtualenv related
bin/
include/
pip-selfcheck.json

# Django related 
# src/<yourproject>/settings/local.py
# static-cdn/  # any collected static files 


# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/




================================================
FILE: README.md
================================================
# eCommerce

[![eCommerce Logo](https://cfe2-static.s3-us-west-2.amazonaws.com/media/courses/ecommerce/images/ecommerce_coding_for_entrepreneurs.jpg)
](https://www.codingforentrepreneurs.com/courses/ecommerce/)

This course will teach you step-by-step to build a eCommerce site from scratch. We'll be using open-source software to create each aspect of a fully functioning eCommerce business.

Full Course is here: [https://www.joincfe.com/courses/ecommerce/](https://www.joincfe.com/courses/ecommerce/)

Below you'll find the related lecture code to any given section and lesson. Enjoy!


# Code

### Section - Hello World

[Intial Commit](../../tree/0927b316e9cdd8b0db01263b6b429e698d38d57a/)


### Section - Products Component

[1 - Your first app Module](../../tree/ed8ceb52830b762d50bbf44f680255168c6f5530/)

[2 - Understanding CRUD](../../tree/aaa75b9c3ffba674e3661175922b99149fd4bdd9/)

[3 - Product Model](../../tree/a80ded7e6ed9a87da9a8029e4e6fe50c18fd4b79/)

[4 - Django Admin](../../tree/311291431e55a783532ff3cd9319e22d77ff92c0/)

[5 - List View](../../tree/ab27c4cc095ae00d51b71545cf6118813c12828f/)

[6 - Detail View](../../tree/b7343749415fb9a6a6a629859684f13a0afbf787/)

[7 - ImageField & FileField](../../tree/08a2426622b6536de6ae16637cc9489eeda5e484/)

[8 - Understanding Lookups](../../tree/6a1116a90d9c24ca4366a3764b20de61a83f52ac/)

[9 - Custom Model Managers](../../tree/f146e4775cb274176897f8e06d842150599aa3c5/)

[10 - Featured & Custom QuerySets](../../tree/8f7cf0ea87b89672f1ca745a251de32598ff5754/)

[11 - SlugField & Signals](../../tree/dc523d5e9aa18a730edd9819c6202fd3ecc20de7/)

[12 - Products URLs](../../tree/959a578bd51964af2a637e2d75423568a8d7972b/)



### Section: Templates

[1 Base Template](../../tree/b34bc1692301719be722bb691c1d67df4e98b455/)

[2 - Include Tag](../../tree/12fd4dd9fcd8616b7b71d8c93a60013aa01350d9/)

[3 Pass Arguments with Include](../../tree/f68b6c15804033937d823f6a707df363901fd6a1/)

[4 - Reusable List View Snippets](../../tree/e59e0938d032e68431c60718f27bfa2abbbd36b0/)

[5 - Reverse for URLs](../../tree/4add77ea1751952f79aaf358bcfecac366ad6ac2/)

[6 - Navbar](../../tree/fc97ee8fd094a47aeb47ad7b25cf2d5a04c78fe8/)

[7 - Template Filters](../../tree/670ddd0ec4cec879a424fe05ac594e863b7dea53/)

[8 - ForLoop Counter & Cycle](../../tree/e47bec09440f7938246c4b9210bd3f131d290dd0/)



### Section: Bootstrap

1 - Adding Bootstrap (no code)

2 - Container vs Container-Fluid (no code)

[3 - Rows And Columns](../../tree/d0e38edee652c5787dc7bf12e2ec2909fa3121f8/)

[4 - Column Sizing](../../tree/b06f0a6661ac37d71be3fe38580bb561f71d2e42/)

[6 - Desinging for Different Browser Sizes with Breakpoints](../../tree/225b29ccbff4aa3098e58d34a434dda495f7fb53/)

[7 - Spacing with Margin & Padding](../../tree/e2eb9bc70e33b4870e87554a81bdee9179f0136d/)

[8 - Navbar](../../tree/696987b4e9144296f681fb229e3420219f9a1026/)

[10 - Integrate to Django](../../tree/6aa47a5627c5f57b3fca3cb52738c96609cc3746/)



### Section: Search Component

[1 - A Basic Search View](../../tree/28aa4043b5ad94a3095ddf3b77fd81a429803ff4/)

[2 - Display the Query to the User](../../tree/e499a814c144497145c689be5626e175b2cd9a6d/)

[3 - Creating the Search Form](../../tree/147efe3fae7b35702050b3f27907c13379a3f85d/)

[4 - Better Lookups with Q](../../tree/54e65447fd0cd9b269c76ac1c9739af9cb1cd7ce/)

[5 - Tag Component](../../tree/883d856330fe86d0ad697fa9cfebf19454b163be/)

[6 - Shell Commands for a Brief Intro to Foreign Keys](../../tree/a85117d052ceaa054f1b025613bbbc46695ea0c0/)

[7 - Search by Related Model](../../tree/908e3e07bc2e3ec5f157f6a06f59ad01395b4a2d/)




### Section: Cart Component

[1 - Cart App](../../tree/ab6ba98698080e5290f0c72e94edc6ebea229a4e/)

[2 - Django Sessions](../../tree/4b2544743e5b3c650231cf10f8f4ba3f85e10382/)

[3 - Cart Model](../../tree/0441dc0e50937eaec64bafa4f9258de70db7efc9/)

[4 - Create A Cart in the View](../../tree/35e8bf075b51d32a7c0fcc1c191700736d64edfc/)

[5 - Cart Model Manager](../../tree/3f9592bd3209ae09d5aa839c87356d7c1c6bc1bd/)

[5 - Cart Model Manager Part 2](../../tree/20368456287ce253d2b51c7f4d2101f52ceb4d35/)

[7 - M2M Changed Signal to Calculate Cart Total](../../tree/c64ba909c1b6af3b5b0502412eef20857cdaa25a/)

[8 - Cart Update View](../../tree/864ef942a2331669d0a1c2385431688888916b22/)

[9 - Add to Cart Form](../../tree/d5cced3c944f39164a36b4ef122ba2369006fc92/)

[10 - Display Cart](../../tree/248c772322547fc7b331fa042627285f67a233a1/)

[11 - Remove Items from the Cart](../../tree/3d7c0fc7fe264eded57ce3244e3ee86d1550a966/)

[12 - Cart Icon & FontAwesome](../../tree/691d5ae69e2b5a8f569be0ede3efd5c9fc7897d3/)



### Section: Checkout Process

[1 - The Roadmap for the Checkout Process](../../tree/14bb24d788f96cb5e8593084428de5dcc0bc43b7/)

[2 - The Order Component](../../tree/e3edacb39b6b5df4ee0b98297df42909784f86c3/)

[3 - Generate the Order ID](../../tree/cfcc598dd86ce7ba795641f7520b58cf21c2e4de/)

[4 - Calculate the Order Total](../../tree/00a2b87d1bfc671d62514679881cbccd62bc2494/)

[5 - Checkout View](../../tree/40e7c81aa1dc18b1878c6097e486624b5163bc83/)

[6 - Math with Decimals and Floats in Python](../../tree/3baac51bf5bf9fe1d1432d140fbdb5de0e3a6752/)

[7 - Upgrading Auth to Prep for Checkout](../../tree/182d7a5da10a5799ca7c053849f39cba426a84eb/)

[8 - Billing Profile Model"](../../tree/3dd97d4cee6c4540410fda0006768bff523e9970/)

[9 - Billing Profile in the Checkout View](../../tree/c0ff6dfdc8991c9a54889a616c327420f1d12939/)

[10 - Guest Checkout Profile](../../tree/e4114e17297c3c437f1cd7e50d7f01e716d1af09/)

[11 - Associate Billing Profile to Order](../../tree/b920068b6d80245344ab424f1e1b33a4e54888e4/)

[12 - Order Manager](../../tree/a0e30cbe85971622c10e8d1bbf930dbaa78695d9/)

[13 - Billing Profile Manager](../../tree/91bf2029c4da79168513dd12fe8ef2f6ac7e18e6/)

[14 - Addresses App](../../tree/159d284645e99feedf94ce5b3693b4a28994c6d8/)

[16 - Associate Addresses to Order](../../tree/3cee508cfe5228a45a919066bbf3bc14c23e824b/)

[17 - Finalize Checkout](../../tree/f38442a8b770d0cea454280fd997a60b712d57ea/)

[18 - Reuse Addresses for Checkout](../../tree/0ba33ba8e29482ed86ea2fe4a956bf7be01e05dd/)

[19 - Checkout Success](../../tree/648e281ed5a8fff4fdf3d9959e0d32ec232a6624/)


### Section: Fast Track to Jquery
[1 - Getting Started](../../tree/bb9938c039d604ab39696ec166210f72edc2521e/)

[2 - A Basic Selector](../../tree/5640cc849c8db492e1d98cc6070b7efb9c6c201c/)

[3 - Selectors Part 2](../../tree/4cd3edb60b092c996de5a5812e007568ac898979/)

[4 - Content Overflow Part 1](../../tree/bcbfb9973673f2d22e1c1af094d7e722237a2652/)

[5 - Data Types, Iteration and Conditionals](../../tree/ec9b8d3277cea37b225ce81e68d00bd46745f5d7/)

[6 - Content Overflow Part 2](../../tree/d4b8fedec4d61d3d6c1f442505c76b43ee613a70/)

[7 - Click Events](../../tree/13c278c521032f6266e411bef97ad996b501379b/)

[8 - Handling form data in jQuery](../../tree/69201626395880675420d187f55744f6a3c267ca/)



### Section: Products & Async

1 - Sync vs Async (no code)

[2 - Ajax-ify a Form](../../tree/1d4d7ca41f515f4c12fed183023fde22463d8058/)

[3 - Handle Ajax in Django with JsonResponse](../../tree/d6acdc28e52f47257afb4c4b3dc6e5f398f39e43/)

[4 - Cart Item Count](../../tree/9455685b79a7ba829799d6dc700dce71c930c5d3/)

[5 - Refresh Cart Ajax](../../tree/dba7c5401106c658a4a29729a1d5fb5efa596c2f/)

[6 & 7 - Refresh Cart Ajax Part 2 & 3](../../tree/7f38a87f80d0c9a32e7e10149af1b19e8aa3d362/)

[8 - Finalize Cart Updating with Ajax](../../tree/c16e30dbd9af01fddef5614f3857de4a7fcace3b/)

[8 - Finalize Cart Updating with Ajax](../../tree/2072edc9f0451a8d9c88e0c6c9394310234331a8/)

[9 - Auto Search](../../tree/c433c4a06ab3d0d199e4a46b390cc98a0328bad1/)

[10 - Display Errors with jQuery Confirm](../../tree/ab040383aeed92a5ab457d25320fc1dddf72bc5d/)

[11 - Ajaxify the Contact Form Part 1 & 2](../../tree/cc35747ceba808fd57350eaf59e51f95a7b091c4/)

[13 - Custom eCommerce JS](../../tree/3431064fde1394e586076b23ba76827e03d626ce/)

[14 - Ajax CSRF Security for Django](../../tree/82111856925f0d9a83eb08c0e937a95ca788d641/)


## Add Ons

### Custom Django User Model

1 - Before we get started (no code)

[2 - Create the Abstract Base User](../../tree/c698e75c82b6145546c93f8d32fec616dfaf1cac/)

[3 - Create the User Model Manager](../../tree/968ec0525e27c3d95f9fc033833264437f90a47b/)

4 - Change Auth User Model to our Custom Model (no code)

[5 - Reload the Database with Fixtures](../../tree/96261517bc1e4c7b2603232569de479ae4c44a9d/)

[6 - Forms & Admin for our Custom User](../../tree/464ff60dd57e8babf0096670f6bb5c62bdaa2e2c/)

[7 - Add a Required Field to the User Model](../../tree/c12eebf5e8c5961b18f65f8741880f40f6cfc99b/)

[8 - Update Login & Register Forms](../../tree/aefcaac8eb1f4f0d7e6f68dde46eb9f82f7e5ff7/)

[9 - Login & Register Views](../../tree/3cccc2c44b9d81fcc4db4ed9bae77a8e23cf263e/)



### Custom Analytics

1 - Getting Started (No Code)

[2 - Craft the Object Viewed Model](../../tree/dcea55fce60dcb56dc933fc0485a95a5a44b0c9d/)

[3 - Get Client IP Address](../../tree/007dd5190b872ef32ab8164efd7631f7bef3a409/)

[4 - A Custom Signal](../../tree/540a9e1f29e896c3145ead7231d76960031bb2c9/)

[5 - Object Viewed Mixin](../../tree/73bfc3e04beee52b9ad6cd503d3b7c8d8ebeb71e/)

[6 - Handle the Object Viewed Signal](../../tree/73bfc3e04beee52b9ad6cd503d3b7c8d8ebeb71e/)

[7 - Handling and Ending User Sessions](../../tree/4c08919bb151553b150b94ae51825517bc2cd460/)

### Stripe Integration

[1 - Getting Started](../../tree/249af4dcc7cbc5496aa0ebca17c3a501021cb5e2/)

[2 - Create Stripe Customer](../../tree/0a835b238f834758ba54db1c6d4978f517dccdc6/)

[3 - Payment Method View & Stripe JS](../../tree/08aab3440a89cea22be0a1053b106b49d8d52f08/)

[4 - Improving Payment Method Form](../../tree/ca4245aabaacc0f3c0f7e6e77902f0312a30686e/)

[5 - Improving Payment Method Form Part 2](../../tree/0ff716c8a8bda2605cf349b19705d46798bb5d1b/)

[6 - Reusable Stripe Module](../../tree/291073b86363a63cb588305e9c258dddc5cad949/)

[7 - Add Card to Customer with Stripe](../../tree/1193c2a22da5e591aca057a4f153fdc3388c23fd/)

[8 - Save Card in Django](../../tree/606f73653342ce361400a8fdddd8f0d917d6552f/)

[9 - Charge the Customer](../../tree/0d4fba2c11c8bf3d4b116c4e619ffb6c41a161de/)

[10 - Putting it All Together](../../tree/252524c4b46a2bad8da4cc000af0234a0227cf11/)

[11 - Guest Card Checkout](../../tree/78924c3cc4ed3f3ed809a69d40a9320f423e5676/)

[12 - Changing Payment Methods](../../tree/90830de29bd3bfcf948527b2fd456f27be37e14c/)

[13 - Improve Card UI - Part 1](../../tree/c1a67d9c6d1c29065d1b09a771e14a7b5a0e8fc2/)

[14 - Improve Card UI - Part 2](../../tree/c1a67d9c6d1c29065d1b09a771e14a7b5a0e8fc2/)

### Mailchimp Integration 

[3 - Setup API Keys](../../tree/f540e03ebff55371f40b971d7fed439d5af886bf/)

[4 - Marketing App](../../tree/4de0f03100f566797a6ac3a2de6b7764169aad24/)

[5 - Mailchimp Class Part 1](../../tree/7ac2eb8e4d747fe7cc4e94c2f01ad87da9b01395/)

[6 - Mailchimp Class Part 2](../../tree/26cd4fe4c3b3b1dff4426aae260578a551c5854a/)

[7 - Mailchimp Class Part 3](../../tree/08dfcb3f273e0993c935372b91b5a47e66ac77c1/)

[8 - Django & Mailchimp](../../tree/128499e857cf64b03a64106eb808b7177d272400/)

[9 - User Email Marketing Preference View](../../tree/73756bab33f261106b9489afe1815f8a6377126e)

[10 - Mailchimp Webhook Handler](../../tree/a6d88a985e21dcd926acf7fb06808459493ff0b9)


### Go Live

1 - Local vs Production Environments (no code)

[2 - New Settings Module](../../tree/f776fc8227c5717b7982274d5de2a12676ab835b/)

[3 - Multiple Settings Modules](../../tree/95542fffb0f225e281557d9616fb8caae85f1a06/)

[4 - Prepare for HTTPs](../../tree/b772608670c45d6654a84b6b0dd014bd6cacc104/)

[5 - The gitignore File](../../tree/0dc38fd34caa8c82850cbab6509b7357b53d904e/)

[6 - Requirements File](../../tree/aaad5cda6f3a3170b6b9430d97db11e84ff191c2/)

[7 - Setup Git Version Control](../../tree/f65d67029ebad9a22f6e63ef66170e533a385f2e/)

[8 - Deploy to Heroku](../../tree/a2041155d977f6d0451aa6220fec0f664bc0cb06/)

[9 - AWS S3 for Static Files](../../tree/90044ca398bbe3b06440d937dc7ea0a645ec593b/)

[10 - Add Custom Domain & HTTPs on Heroku](../../tree/3689bfcd72670fa59ceaa864d58927f2c2fc53d7/)

[11 - Live Environment Variables](../../tree/e3210c4ae568e5e1e48a1d70ad2e9b67cf83aa63/)

[12 - Error Views and Templates](../../tree/764a8acba104c60676d83574baf7c0c0806501ad/)

[13 - Setup Email to Help Solve Server Errors](../../tree/b151d182dc5ae1e380c2959a09a8eb6e2fe2fcc8/)

[14 - Using Heroku Locally](../../tree/6c24c03aaf84a4fb02d9cc855815ab0e581798ff)


### Account & Settings

[1 - User Account Home](../../tree/e56ea8420170c40b420780a48cbf1087a5081525/)

[2 - Naming & Dropdown](../../tree/dc1dd608ef6407d11b4d5b5e2784220fbe8d1ff4/)

[3 - Account Bootstrap Cards](../../tree/c07ba032b597191f043a4ac9cd75d10ee840afcb/)

[4 - Link Account Bootstrap Cards](../../tree/287fbca8d84c1a9112e6cb3adeba1c8a15693fcc/)

[5 - Password Reset and Change](../../tree/55d62beec3b7374e955df8b9b6e6ddbde5997abc/)

[6 - send_email and get_template](../../tree/e3c86dec0b7b985c8b1d403786d0f7a201f2767b/)

[7 - Email Activation](../../tree/30f9aa0d6605014b52f80b85d139597ef6b0fcf6/)

[8 - Custom QuerySet for Confirmable Activations](../../tree/4fe792b8d5e868a813f8b521cda2660fe61048ed/)

[9 - Email Activation View](../../tree/0904726b55184994ac180bc0c0d55edb2a97feaa/)

[10 - Email Reactivation](../../tree/3b9e78cece5c834043bd41b319a78109badf2253/)

[11 - Improved Login Form & View](../../tree/359119ff0efdb482ec1e6133877ef251e3a4ebf5/)

[12 - Login Form for Confirmation Emails](../../tree/a7f53f7598259f711f62957a4588dc187895e07d/)

[13 - Upgrading the Guest Checkout Form](../../tree/58cac4150c5c5b724feb2f92e795ded4c162e7df/)

[14 - Edit Account Details](../../tree/c471c3a04f46e7b851197de6a217fa6a68ec67b7/)

[15 - User Product History View](../../tree/e50e38a7f01c9348866a92e8c7e2e772ba229763/)

[16 - Orders & Order Detail](../../tree/e92f5c4ac8413fc9988510b0889a5a582cbae462/)

[17 - Final Addresses on Order](../../tree/d076db0f36de01abe10e0474ac09606e33800c44/)

[18 - Addresses List View](../../tree/065d6e0fd246aa1510b835d6eb6bf732e104fc8d/)

[19 and 20 - Update & Create Addresses Part 1 & 2](../../tree/a89b4cd06d42648b7920a301d7c70969838b9732/)

### Selling Digital Items

[1 - Digital Products & Cart](../../tree/69f842b8e19470eba122a5566a2da5d23880d388/)

[2 - Shipping-less Checkout](../../tree/14cae3f833034abaf0190259851a09a40efdbc65/)

[3 - Product Purchases](../../tree/49bb74466bd5da3464c2cb608d150336ac2eba48/)

[4 - Handling Products Being Purchased](../../tree/3cfa6c4d7ffbbd83b8246fc7984bb0f8bb448ea9/)

[5 - Display of Refunded Items](../../tree/c2d95bcf338b69eec962cff6aa92a409ad204ec3/)

[6 - Library View](../../tree/4d1f98e4c81c9229945a1a3342297b4f52e680d1/)

[7 - Library View for Products Only](../../tree/f1e3b4618699c73034e1ac85f4bf27ba4025879a/)

[8 - Product File Model](../../tree/1e74caa60b3b6f52ced214a5169e111ac8399e2a/)

[9 - Changing File Field Storage to Protected Location](../../tree/a7cfdd8849d8bc22d78f1ce565b653ba32967262/)

[10 - Download Product File Part 1](../../tree/e3463e00d6257726d77dcf3ad72caa77e89ed1db/)

[11 - Download Product File Part 2](../../tree/91cb57960416e4ab5701f0a2cc4e7b158f47985f/)

[12 - Perform the File Download](../../tree/6d92ca188e18eca8d4d4b7e1b017a010300e8c11/)

[13 - Checking Download Permissions](../../tree/fe631500b7a4f69ab48b513cbf5d5be89d5a5e5c/)

[14 - In Library Display Part 1](../../tree/4f1b64f1df2b67d98bf8a0d81dc57947409ad2ea)

[15 - In Library Display Part 2 with Ajax](../../tree/46be780b0f0dd524d6eb4bbea63c9f0b2c4b9b7c)

[16 - AWS S3 File Upload](../../tree/96d664722a95dab2895313ef3731c84093d3596d/)

[17 - Fixing the Upload Path](../../tree/75c4e175bf0c4516a6ee91e2f1a7280f998ba6bd/)

[18 - Creating the AWS Download Class](../../tree/d1d5cb5820d813a87d184b9eb2c34b0ff54d3c76/)

[19 - Using the AWS Download Client](../../tree/a879fcc03d0225e343212b17d4c6dcb43578fdc7/)

[20 - A Custom Filename](../../tree/ed23c9b95d7b84de9447bcfbeacfd35d4cfdcd08/)


### Graphs and Sales

[1 - Setup the View](../../tree/2b65b93648d4211e64cc02022a0988a96ac53b9f/)

[2 - Add Context for the Order Data](../../tree/f6e5671c5c9170f3e0fdd3427acb0c49b3f60751/)

[3 - Intuitive Recent Order Total](../../tree/50326ef1c082d7bcdbe9351938043b4af28f68b7/)

[4 - Aggregate & Annotate](../../tree/0438bd0af6b4559fd1b80b9456a32e5b2262c6d4/)

[5 - Get Data by Custom QuerySet](../../tree/8bdec3c85ec8b3a842816efbc4d80223a6d862dd/)

[6 - Intro to Datetime Module](../../tree/b9f8bb1775c8037326ba3a095a224a88cf6a0775/)

[7 - Filter by Range of Time](../../tree/0a8a304296f926ad0bba4fa66dff566b7e20ecbb/)

[8 - Chart-js Intro](../../tree/bd9c8861e58feb5dc2ce13103a1aa21c29e7638b/)

[9 - Using Ajax to Render Charts](../../tree/a60c2fb9476111de483a5fcda4c7262a10f66392/)

[10 - Display True Data](../../tree/dd8a626fbb6dc43efc0799f652a808f03b7542f8/)

[11 - Cleanup](../../tree/fe478427f789ff2ed9110e8e3739d6e9975fe714/)

[12 - Inline Js to External](../../tree/f827bac20fc98a85ff84232ed3ea4ec4ea877f56/)


================================================
FILE: ecommerce.code-workspace
================================================
{
	"folders": [
		{
			"path": "."
		}
	],
	"settings": {}
}

================================================
FILE: ecommerce.sublime-project
================================================
{
	"folders":
	[
		{
			"path": "."
		}
	]
}


================================================
FILE: ecommerce.sublime-workspace
================================================
{
	"auto_complete":
	{
		"selected_items":
		[
			[
				"pos",
				"postal_code"
			],
			[
				"add",
				"address_line_2"
			],
			[
				"line",
				"line1"
			],
			[
				"is",
				"is_done"
			],
			[
				"ship",
				"shipping_address"
			],
			[
				"bil",
				"billing_address_id"
			],
			[
				"Bil",
				"BillingProfile"
			],
			[
				"Bill",
				"BillingProfileManager"
			],
			[
				"obj",
				"order_obj"
			],
			[
				"order",
				"order_obj"
			],
			[
				"billing",
				"billing_profile"
			],
			[
				"car",
				"cart_removal_qs"
			],
			[
				"gues",
				"guest_email_id"
			],
			[
				"cl",
				"cleaned_data"
			],
			[
				"bill",
				"billing_profile"
			],
			[
				"next",
				"next_post"
			],
			[
				"is_",
				"is_safe_url"
			],
			[
				"user",
				"user_checkout"
			],
			[
				"de",
				"Decimal"
			],
			[
				"nu",
				"num1"
			],
			[
				"cart",
				"cart_obj"
			],
			[
				"ran",
				"random_string_generator"
			],
			[
				"pr",
				"product_id"
			],
			[
				"Pr",
				"ProductDetailSlugView"
			],
			[
				"prd",
				"product_id"
			],
			[
				"new",
				"new_obj"
			],
			[
				"Car",
				"CartManager"
			],
			[
				"tag",
				"tag_set"
			],
			[
				"drop",
				"dropdown-menu"
			],
			[
				"nav",
				"navbar"
			],
			[
				"get",
				"get_object_or_404"
			],
			[
				"fea",
				"featured"
			],
			[
				"file",
				"filename"
			],
			[
				"conta",
				"contact_form"
			],
			[
				"con",
				"contact_form"
			],
			[
				"mar",
				"margin-bottom"
			],
			[
				"en",
				"environ"
			],
			[
				"image",
				"image_path"
			],
			[
				"err",
				"errMsg\tlet"
			],
			[
				"in",
				"instanceof\tkeyword"
			],
			[
				"Vid",
				"VideoManager"
			],
			[
				"Vide",
				"VideoQuerySet"
			],
			[
				"q",
				"query"
			],
			[
				"quer",
				"query"
			],
			[
				"u",
				"unique_slug_generator"
			],
			[
				"col-",
				"col-sm-12"
			],
			[
				"h",
				"homeImageList\tproperty"
			],
			[
				"se",
				"searchQuery\tproperty"
			],
			[
				"r",
				"routeSub\tproperty"
			],
			[
				"Av",
				"ActivatedRoute\talias"
			],
			[
				"p",
				"push\tmethod"
			],
			[
				"max",
				"max-height"
			],
			[
				"margin-",
				"margin-bottom"
			],
			[
				"min",
				"min-height"
			],
			[
				"by",
				"bypassSecurityTrustResourceUrl\tmethod"
			],
			[
				"Pip",
				"PipeTransform\talias"
			],
			[
				"imp",
				"implements\tkeyword"
			],
			[
				"cons",
				"console\tvar"
			],
			[
				"rou",
				"RouterModule\talias"
			],
			[
				"Rou",
				"RouterModule\talias"
			],
			[
				"fu",
				"function\tkeyword"
			],
			[
				"bas",
				"basil3\tlet"
			],
			[
				"login",
				"loginUrl"
			],
			[
				"lo",
				"login"
			],
			[
				"data",
				"dataId"
			],
			[
				"gen",
				"generateEditForm"
			],
			[
				"cfe-",
				"cfe-media-edit"
			],
			[
				"auth",
				"author"
			],
			[
				"aut",
				"author"
			],
			[
				"text",
				"textarea"
			],
			[
				"form",
				"formData"
			],
			[
				"object",
				"objectId"
			],
			[
				"co",
				"contentTxt"
			],
			[
				"content",
				"contentHolder"
			],
			[
				"html",
				"htmlStart_"
			],
			[
				"per",
				"permission_classes"
			],
			[
				"a",
				"authentication"
			],
			[
				"re",
				"responseJSON"
			],
			[
				"res",
				"responseData"
			],
			[
				"fo",
				"formResponse"
			],
			[
				"max-",
				"max-height"
			],
			[
				"time",
				"timestamp"
			],
			[
				"like",
				"likeUrl"
			],
			[
				"cu",
				"customersDjango"
			],
			[
				"Lis",
				"ListView"
			],
			[
				"save",
				"save_path"
			],
			[
				"email",
				"email_message"
			],
			[
				"inb",
				"inbox_item_list"
			],
			[
				"ea",
				"email_message"
			],
			[
				"ema",
				"email_message"
			],
			[
				"acc",
				"access_secret"
			],
			[
				"blog",
				"blog-list"
			],
			[
				"BlogList",
				"blogListController"
			],
			[
				"font",
				"font-size"
			],
			[
				"img",
				"img_r"
			],
			[
				"sel",
				"sel_soup"
			],
			[
				"web",
				"webdriver"
			],
			[
				"my",
				"my_num_list"
			],
			[
				"my_",
				"my_num_list"
			],
			[
				"str",
				"str"
			],
			[
				"Post",
				"PostSerializer"
			],
			[
				"query",
				"queryset"
			],
			[
				"read",
				"read_time_min"
			],
			[
				"rea",
				"read_time_minutes"
			],
			[
				"count",
				"count_words"
			],
			[
				"cont",
				"content_type"
			],
			[
				"Co",
				"CommentForm"
			],
			[
				"Commen",
				"CommentForm"
			],
			[
				"H",
				"HttpResponseRedirect"
			],
			[
				"Comm",
				"CommentManager"
			],
			[
				"parent",
				"parent_qs"
			],
			[
				"parent_",
				"parent_id"
			],
			[
				"Ht",
				"HttpResponseRedirect"
			],
			[
				"obje",
				"objects"
			],
			[
				"pare",
				"parent_id"
			],
			[
				"comm",
				"CommentManager"
			],
			[
				"Com",
				"Comment"
			],
			[
				"cle",
				"clean_parent_id"
			],
			[
				"COmm",
				"CommentManager"
			],
			[
				"conten",
				"content_type"
			],
			[
				"conte",
				"contentItem"
			],
			[
				"mark",
				"markedContent"
			],
			[
				"titl",
				"titleItem"
			],
			[
				"tit",
				"titleValue"
			],
			[
				"use",
				"username"
			],
			[
				"get_o",
				"get_object"
			],
			[
				"usr",
				"username"
			],
			[
				"get_obj",
				"get_object_or_404"
			]
		]
	},
	"buffers":
	[
	],
	"build_system": "",
	"build_system_choices":
	[
	],
	"build_varint": "",
	"command_palette":
	{
		"height": 87.0,
		"last_filter": "mark",
		"selected_items":
		[
			[
				"mark",
				"Markdown Preview: Preview in Browser"
			],
			[
				"instal",
				"Package Control: Install Package"
			],
			[
				"ins",
				"Package Control: Install Package"
			],
			[
				"pack",
				"Package Control: Install Package"
			],
			[
				"mar",
				"Markdown Preview: Preview in Browser"
			],
			[
				"markd",
				"Markdown Preview: Preview in Browser"
			],
			[
				"markdown",
				"Markdown Preview: Preview in Browser"
			],
			[
				"",
				"Convert Case: Lower Case"
			],
			[
				"package",
				"Package Control: List Packages"
			],
			[
				"install",
				"Package Control: Install Package"
			]
		],
		"width": 485.0
	},
	"console":
	{
		"height": 125.0,
		"history":
		[
		]
	},
	"distraction_free":
	{
		"menu_visible": true,
		"show_minimap": false,
		"show_open_files": false,
		"show_tabs": false,
		"side_bar_visible": false,
		"status_bar_visible": false
	},
	"expanded_folders":
	[
		"/Users/cfe/Dev/ecommerce"
	],
	"file_history":
	[
		"/Users/cfe/Dev/ecommerce/src/ecommerce/settings.py",
		"/Users/cfe/Dev/ecommerce/src/addresses/admin.py",
		"/Users/cfe/Dev/ecommerce/src/addresses/forms.py",
		"/Users/cfe/Dev/ecommerce/src/addresses/models.py",
		"/Users/cfe/Dev/ecommerce/src/billing/models.py",
		"/Users/cfe/Dev/ecommerce/src/addresses/templates/addresses/form.html",
		"/Users/cfe/Dev/ecommerce/src/ecommerce/urls.py",
		"/Users/cfe/Dev/ecommerce/src/addresses/views.py",
		"/Users/cfe/Dev/ecommerce/src/accounts/views.py",
		"/Users/cfe/Dev/ecommerce/src/orders/models.py",
		"/Users/cfe/Dev/ecommerce/src/addresses/templates/addresses/prev_addresses.html",
		"/Users/cfe/Dev/ecommerce/src/carts/templates/carts/checkout.html",
		"/Users/cfe/Dev/ecommerce/src/carts/templates/carts/checkout-done.html",
		"/Users/cfe/Dev/ecommerce/src/carts/urls.py",
		"/Users/cfe/Dev/ecommerce/parse_git_log.py",
		"/Users/cfe/Dev/ecommerce/src/carts/views.py",
		"/Users/cfe/Dev/ecommerce/README.md",
		"/Users/cfe/Dev/ecommerce/parsed_log.md",
		"/Users/cfe/Dev/ecommerce/src/billing/admin.py",
		"/Users/cfe/Dev/ecommerce/src/accounts/templates/accounts/snippets/form.html",
		"/Users/cfe/Dev/ecommerce/src/accounts/forms.py",
		"/Users/cfe/Dev/ecommerce/src/accounts/models.py",
		"/Users/cfe/Dev/ecommerce/src/accounts/admin.py",
		"/Users/cfe/Dev/ecommerce/notes/checkout_process.md",
		"/Users/cfe/Dev/ecommerce/src/ecommerce/views.py",
		"/Users/cfe/Dev/ecommerce/src/templates/base/navbar.html",
		"/Users/cfe/Dev/ecommerce/src/ecommerce/forms.py",
		"/Users/cfe/Dev/ecommerce/src/templates/auth/login.html",
		"/Users/cfe/Dev/ecommerce/src/carts/models.py",
		"/Users/cfe/Dev/ecommerce/src/ecommerce/utils.py",
		"/Users/cfe/Dev/ecommerce/src/products/models.py",
		"/Users/cfe/Dev/ecommerce/src/tags/models.py",
		"/Users/cfe/Dev/ecommerce/src/orders/admin.py",
		"/Users/cfe/Dev/ecommerce/src/carts/templates/carts/home.html",
		"/Users/cfe/Dev/ecommerce/src/products/utils.py",
		"/Users/cfe/Dev/ecommerce/src/orders/utils.py",
		"/Users/cfe/Dev/ecommerce/src/templates/base/css.html",
		"/Users/cfe/Dev/ecommerce/src/products/views.py",
		"/Users/cfe/Dev/ecommerce/src/products/templates/products/detail.html",
		"/Users/cfe/Dev/ecommerce/src/products/templates/products/snippets/update-cart.html",
		"/Users/cfe/Dev/ecommerce/src/carts/admin.py",
		"/Users/cfe/Dev/ecommerce/src/search/urls.py",
		"/Users/cfe/Dev/ecommerce/src/tags/admin.py",
		"/Users/cfe/Dev/ecommerce/src/tags/shell_commands.py",
		"/Users/cfe/Dev/ecommerce/src/search/templates/search/view.html",
		"/Users/cfe/Dev/ecommerce/src/search/templates/search/snippets/search-form.html",
		"/Users/cfe/Dev/ecommerce/src/search/views.py",
		"/Users/cfe/Dev/ecommerce/src/search/models.py",
		"/Users/cfe/Dev/ecommerce/src/search/templates/search/search_form.html",
		"/Users/cfe/Dev/ecommerce/src/templates/bootstrap/example.html",
		"/Users/cfe/Dev/ecommerce/src/templates/base.html",
		"/Users/cfe/Dev/ecommerce/src/templates/home_page.html",
		"/Users/cfe/Dev/ecommerce/src/products/templates/products/list.html",
		"/Users/cfe/Dev/ecommerce/src/templates/auth/register.html",
		"/Users/cfe/Dev/ecommerce/src/templates/bootstrap-section/base.html",
		"/Users/cfe/Dev/ecommerce/src/templates/contact/view.html",
		"/Users/cfe/Dev/ecommerce/src/products/urls.py",
		"/Users/cfe/Dev/ecommerce/src/products/templates/products/snippets/card.html",
		"/Users/cfe/Dev/ecommerce/src/products/admin.py",
		"/Users/cfe/Dev/ecommerce/src/templates/base/js.html",
		"/Users/cfe/Dev/ecommerce/src/products/templates/products/featured-detail.html",
		"/Users/cfe/Dev/ecommerce/src/products/understanding_crud.md",
		"/Users/cfe/Dev/ecommerce/src/static_my_proj/css/main.css",
		"/Users/cfe/Dev/cfe-s3-upload/backend/src/templates/upload.html",
		"/Users/cfe/Dev/cfe-s3-upload/backend/src/cfehome/urls.py",
		"/Users/cfe/Dev/cfe-s3-upload/backend/src/files/config_aws.py",
		"/Users/cfe/Dev/cfe-s3-upload/backend/src/cfehome/settings/base.py",
		"/Users/cfe/Dev/cfe-s3-upload/backend/src/cfehome/settings/local.py",
		"/Users/cfe/Dev/cfe-s3-upload/backend/src/cfehome/settings/production.py",
		"/Users/cfe/Dev/cfe-s3-upload/backend/src/credentials.py",
		"/Users/cfe/Dev/cfe-s3-upload/backend/src/cfehome/credentials.py",
		"/Users/cfe/Dev/django-s3-upload/credentials.py",
		"/Users/cfe/Dev/django-s3-upload/src/credentials.py",
		"/Users/cfe/Dev/basics/src/templates/posts/listview.html",
		"/Users/cfe/Dev/basics/src/posts/migrations/0006_auto_20170727_1653.py",
		"/Users/cfe/Dev/basics/src/pages/models.py",
		"/Users/cfe/Dev/basics/src/cfebasic/urls.py",
		"/Users/cfe/Dev/basics/src/templates/navbar.html",
		"/Users/cfe/Dev/basics/src/templates/javascript.html",
		"/Users/cfe/Dev/basics/src/templates/base.html",
		"/Users/cfe/Dev/basics/src/templates/contact.html",
		"/Users/cfe/Dev/basics/src/templates/about.html",
		"/Users/cfe/Dev/basics/src/templates/home.html",
		"/Users/cfe/Dev/basics/src/cfebasic/settings.py",
		"/Users/cfe/Dev/basics/src/posts/views.py",
		"/Users/cfe/Dev/basics/src/pages/views.py",
		"/Users/cfe/Dev/trydjango1-11/README.md",
		"/Users/cfe/Dev/trydjango1-11/LICENSE",
		"/Users/cfe/Dev/trydjango1-11/.gitignore",
		"/Users/cfe/Dev/trydjango1-11/requirements.txt",
		"/Users/cfe/Dev/trydjango1-11/src/muypicky/settings/__init__.py",
		"/Users/jmitch/Dropbox/cfe/v2/src/accounts/signals.py",
		"/Users/jmitch/Dropbox/cfe/v2/src/analytics/models.py",
		"/Users/jmitch/Dropbox/cfe/v2/src/accounts/views.py",
		"/Users/cfe/Dev/geo2/.gitignore",
		"/Users/cfe/Dev/geo2/src",
		"/Users/cfe/Dev/djangular/backend/src/.env",
		"/Users/cfe/Dev/djangular/backend/src/tryangular/settings/base.py",
		"/Users/cfe/Dev/djangular/backend/src/tryangular/aws/utils.py",
		"/Users/cfe/Dev/djangular/backend/src/tryangular/aws/conf.py",
		"/Users/cfe/Dev/djangular/backend/src/tryangular/wsgi.py",
		"/Users/cfe/Dev/djangular/backend/src/tryangular/__init__.py",
		"/Users/cfe/Dev/djangular/backend/src/tryangular/settings/local.py",
		"/Users/cfe/Dev/djangular/client/src/app/home/home.component.ts",
		"/Users/cfe/Dev/djangular/backend/src/videos/models.py",
		"/Users/cfe/Dev/djangular/backend/src/videos/api/serializers.py",
		"/Users/cfe/Dev/djangular/backend/src/tryangular/settings/production.py",
		"/Users/cfe/Dev/djangular/backend/src/videos/migrations/0006_auto_20170426_2258.py",
		"/Users/cfe/Dev/djangular/backend/src/tryangular/aws/__init__.py",
		"/Users/cfe/Downloads/credentials (1).csv",
		"/Users/cfe/Dev/djangular/.gitignore",
		"/Users/cfe/Dev/djangular/backend/src/tryangular/settings/__init__.py",
		"/Users/cfe/Dev/djangular/backend/src/runtime.txt",
		"/Users/cfe/Dev/djangular/backend/src/tryangular/old_settings.py",
		"/Users/cfe/Dev/djangular/backend/src/staticheroku/mediaheroku/images/blank.txt",
		"/Users/cfe/Dev/djangular/backend/src/staticheroku/mediaheroku/blank.txt",
		"/Users/cfe/Dev/djangular/backend/src/requirements.txt",
		"/Users/cfe/Dev/djangular/backend/src/mediaheroku/blank.txt",
		"/Users/cfe/Dev/djangular/backend/src/mediaheroku/blank",
		"/Users/cfe/Dev/djangular/backend/src/Procfile",
		"/Users/cfe/Dev/djangular/backend/src/.gitignore",
		"/Users/cfe/Dev/djangular/backend/src/videos/utils.py",
		"/Users/cfe/Dev/djangular/backend/src/templates/500.html",
		"/Users/cfe/Dev/djangular/backend/src/templates/404.html",
		"/Users/cfe/Dev/djangular/backend/src/tryangular/urls.py",
		"/Users/cfe/Dev/djangular/backend/src/videos/api/urls.py",
		"/Users/cfe/Dev/djangular/client/src/app/video-detail/video-detail.component.html",
		"/Users/cfe/Dev/djangular/client/src/app/search/search.component.ts"
	],
	"find":
	{
		"height": 40.0
	},
	"find_in_files":
	{
		"height": 132.0,
		"where_history":
		[
			"/Users/jmitch/Dropbox/cfe/v2/src",
			"/Users/cfe/Dev/djangular/client/src/app",
			"/Users/jmitch/Desktop/ecommerce-2/src",
			"/Users/jmitch/Dropbox/projects/kpj",
			"/Users/jmitch/Dropbox/projects/kpj/kpj",
			"/Users/jmitch/Dropbox/projects/",
			"/Users/jmitch/Dropbox/projects/kpj/kpj",
			"<open files>",
			"/Users/jmitch/Dropbox/projects/kpj/kpj",
			"/Users/jmitch/Dropbox/projects/kpj",
			"/Users/jmitch/Dropbox/cfe/src"
		]
	},
	"find_state":
	{
		"case_sensitive": false,
		"find_history":
		[
			"Login",
			"Session",
			"fileUploadComplete",
			"$.alert",
			"uploadFile",
			"courseId",
			"username",
			"file_bucket",
			".send",
			"end_session",
			"user_logged_in",
			"geoip",
			"object_viewed",
			"console.log",
			"videoListDefaultImage",
			"\"assets/",
			"from",
			"jquery",
			"login",
			".load-comments",
			"load-comments",
			"parent()",
			">Edit",
			"edit",
			"formatErrorMsg",
			"authUsername",
			"owner",
			"getComments",
			"likes",
			"url",
			"crispy",
			"Comment",
			"charts",
			"markdown",
			"comment",
			"reportlab",
			"$http",
			"get_transactions",
			"ProductUpdateView",
			"delete all",
			"jmitch-#",
			"AddressSelectFormView",
			"order_address",
			"\"",
			"item_it",
			"trydjango18",
			"questions_notification",
			"app.task",
			"needs_rep",
			"sendgrid",
			"celerybeat-schedule.db",
			"get_next_lecture",
			"lecture_quiz_result",
			"quiz",
			"url",
			"reverse",
			"module-box",
			"slug",
			"lang",
			"send_mail",
			"get_user",
			"ppe_4",
			"as_view",
			"\"join\"",
			"saftey",
			"Saftey Trianing i",
			"Training on new pesticides prior to first use",
			"transaction",
			"render_to",
			"render_to_pdf",
			"render_to",
			"DeleteView",
			"welcome_",
			"welcome",
			"all.html",
			"$.ajax",
			"ajax",
			"wistia",
			"upload",
			"review",
			"review now",
			"review_chemicals",
			"lectures_admin",
			"upload_bulk",
			"ChemicalsViewAdmin",
			"filter(active=F",
			"active",
			"LectureQuizAdminView",
			"formview",
			"$.ajax",
			"ajax",
			"clean",
			"keep",
			"questionanswer",
			"initial",
			"get_lecture",
			"slug",
			"LectureDetailView",
			"get_lecture",
			"get_next_lecture",
			"lecture_quiz",
			"edit_lecture",
			"single_lecture",
			"single",
			"form.as",
			"question.as",
			"question",
			"method",
			"csv",
			"ceu",
			"login",
			"easy",
			"grand",
			"pricing",
			"cost",
			"paginator",
			"question",
			"lecturequestion",
			"question",
			"next",
			"take_quiz",
			"after ",
			"href",
			"take_quiz",
			"start",
			"Coding",
			"Coding For Entrepreneurs",
			"Coding for Entrepreneurs"
		],
		"highlight": false,
		"in_selection": false,
		"preserve_case": false,
		"regex": false,
		"replace_history":
		[
			"\"/static/ang/assets/",
			".cfe-load-comments",
			"jmitch=#",
			"'",
			"ecommerce2",
			"Control Guidance Solutions, LLC",
			"class=\"fa fa-check fa-2x\"",
			"img/apple-touch-icon-152.png",
			"{})",
			"render(request,",
			"render(",
			")",
			"render(request,",
			"Coding For Entrepreneurs",
			"CodingForEntrepreneurs.com",
			"Coding For Entrepreneurs",
			"CodingForEntrepreneurs.com"
		],
		"reverse": false,
		"show_context": false,
		"use_buffer2": false,
		"whole_word": false,
		"wrap": true
	},
	"groups":
	[
		{
			"sheets":
			[
			]
		}
	],
	"incremental_find":
	{
		"height": 40.0
	},
	"input":
	{
		"height": 52.0
	},
	"layout":
	{
		"cells":
		[
			[
				0,
				0,
				1,
				1
			]
		],
		"cols":
		[
			0.0,
			1.0
		],
		"rows":
		[
			0.0,
			1.0
		]
	},
	"menu_visible": true,
	"output.doc":
	{
		"height": 0.0
	},
	"output.find_results":
	{
		"height": 508.0
	},
	"pinned_build_system": "",
	"project": "ecommerce.sublime-project",
	"replace":
	{
		"height": 76.0
	},
	"save_all_on_build": true,
	"select_file":
	{
		"height": 0.0,
		"last_filter": "",
		"selected_items":
		[
			[
				"email",
				"templates/team/email_instructions.html"
			]
		],
		"width": 0.0
	},
	"select_project":
	{
		"height": 0.0,
		"last_filter": "",
		"selected_items":
		[
		],
		"width": 0.0
	},
	"select_symbol":
	{
		"height": 0.0,
		"last_filter": "",
		"selected_items":
		[
		],
		"width": 0.0
	},
	"selected_group": 0,
	"settings":
	{
	},
	"show_minimap": false,
	"show_open_files": true,
	"show_tabs": true,
	"side_bar_visible": true,
	"side_bar_width": 224.0,
	"status_bar_visible": true,
	"template_settings":
	{
	}
}


================================================
FILE: fasttracktojquery/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
    <style>
    /*body {
      background-color: red;
    }*/
    h1 {
      color: green;
    }

    #header-3 {

    }
    .description {
      width: 250px;
      height: 300px;
      padding: 30px 10px;
    }
  </style>

  </head>
  <body>
    <div class='container'>
      <div class='row'>
        <div class='col mx-auto'>
          <h3>Form</h3>
    <form class='new-content-form' method="POST" action='/some/url/link'>
      <textarea name='content' class='form-control'></textarea>
      <input type='submit' value='Save' />
    </form>
  </div>
</div>
  </div>

  <div class='formDataSubmitted'>


  </div>





<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>





    <h1 class='header'>Hello, world!</h1>
    <h1 class='header'>Hello, world!</h1>
    <h1 class='header' id='header-3'>Header 3</h1>
    <h1 class='header'>Hello, world!</h1>
    
    <p class='description'><a href='/abc/'>Some Link</a></p>
    <p class='description'>Another Paragraph</p>
    <p class='description'>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam pulvinar eros sed neque maximus, vel volutpat odio facilisis. Pellentesque convallis laoreet dapibus. Fusce sit amet elementum mauris, id fermentum risus. Integer ultrices velit at nunc egestas, vel iaculis est lobortis. Integer mattis sagittis ligula vel viverra. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce nec lectus ultricies, scelerisque nisl ut, ullamcorper libero. Aliquam at lacinia metus, sed hendrerit mi. Etiam euismod ultrices orci, non vestibulum arcu porta rhoncus. Aliquam bibendum auctor magna non consequat. Morbi varius, sapien a finibus mollis, augue enim sodales nisi, vel finibus tellus quam nec quam. Vestibulum venenatis nisl id justo molestie, ac imperdiet quam commodo.

Nunc finibus odio sagittis risus tincidunt hendrerit. Etiam sapien nisl, congue eget ex in, egestas scelerisque risus. Quisque odio lectus, scelerisque ac nisl ut, commodo rhoncus magna. Praesent consectetur turpis nec ante maximus, sed tristique enim ultrices. Nulla libero massa, bibendum eget semper vitae, mollis sit amet quam. Suspendisse euismod aliquam dolor at suscipit. Nullam faucibus tincidunt venenatis. Pellentesque id quam aliquam libero lacinia aliquet at id libero. Praesent ut ante ligula. Mauris quis est interdum, elementum nibh nec, condimentum odio. Suspendisse interdum sapien tortor, a efficitur elit varius sed. Phasellus eu nisl enim. Nulla ultricies feugiat eros sit amet finibus. Maecenas tellus eros, pulvinar non luctus ac, faucibus ut neque. Praesent non luctus quam.</p>
    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
   <script src='https://code.jquery.com/jquery-3.2.1.min.js'></script>
<!--    <script type="text/javascript">
      $(document).ready(function(){
          var num = 124
          var someString = "some string"
          // some_array = [num, 123, 12333, "an so on"]
          var someArray = [num, 9, 12333, "an so on"]
          var someBool = true // true
          $.each(someArray, function(index, obj){
              // console.log(index, obj)
              // 10 % 3  == 1
              // 9 % 3 == 0
              if ( obj %2 == 0 && someBool) {
                console.log(obj, "is even")
              } else if (obj%3 == 0 && someBool){
                console.log(obj, "by 3")
              } else {
                console.log(obj, "false and/or is not even")
              }
          })



      }) 


   </script> -->





   <!-- <script type="text/javascript">
      $(document).ready(function(){
        // jquery is ready to roll
        // $(selector)
        // $('body').css("background-color", "red")
        var $description = $(".description")

        // $description.css("height", "300px").css("width", "250px")
        console.log($description.length) // if 1 then exists// print()
        console.log($description.css("height")) // print()
        console.log($description.height())

        // if currentElementHeight > builtInHeight
        // add $description.css("overflow", "scroll")


        setTimeout(function(){
            // $('body').css("background-color", "red")
            $('h1').css("color", "purple")
            $('h1:nth-child(2)').text("Hello again!")
            $('#header-3').text("Hello again header 3!")
            $(".header").css("background-color", "green").css("padding", "30px")
        }, 2000) // in ms
      })
   </script> -->







   <!-- <script type="text/javascript">
      $(document).ready(function(){
        var $descriptionItems = $(".description")
        // console.log($descriptionItems.length) // 0, 1, 2

        $.each($descriptionItems, function(index, obj){
          var item = $(this) 
          var actualHeight = item[0].scrollHeight
          var shouldBeHeight = item.height()
          // console.log(actualHeight, shouldBeHeight)
          if (actualHeight > shouldBeHeight + 50){
            item.css("overflow-y", "scroll")
          }
          // console.log(index, item.height())
          // console.log(index, obj)
        })



        var header3 = $("#header-3")
        header3.click(function(event){
          var $this = $(this)
          console.log($this)
          console.log(event)
          window.location.href = 'http://www.google.com/'
        })


        var descriptionLinks = $(".description a")
        descriptionLinks.click(function(event){
          console.log(event)
          event.preventDefault()
          var $this = $(this)
          var href = $this.attr("href")
          console.log(href)
          alert(href)
          window.location.href =href

        })
      })
   </script>

 -->









 <script type="text/javascript">
    $(document).ready(function(){
      var contentForm = $(".new-content-form")
      contentForm.submit(function(event){
        event.preventDefault()
        var $this = $(this)
        //console.log(contentForm.serialize())
        var textAreaContent = $this.find('textarea')
        // console.log(textAreaContent.attr("name"))
        //console.log(textAreaContent.val())
        var formMethod = $this.attr("method") // contentForm.attr("method")
        var formAction = $this.attr("action")
        var data = {
            "content": textAreaContent.val(),
            "method": formMethod,
            "action": formAction
        }

        $('.formDataSubmitted').text(textAreaContent.val() + " method is " + formMethod)

        textAreaContent.val("")


        // $.ajax({
        //   url:
        //   method:
        //   data:
        // })

      })

    })


 </script>



    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>
  </body>
</html>

================================================
FILE: notes/checkout_process.md
================================================
# Checkout Process

1. Cart -> Checkout View
    ?
    - Login/Register or Enter an Email (as Guest)
    - Shipping Address
    - Billing Info
        - Billing Address
        - Credit Card / Payment

2. Billing App/Component
    - Billing Profile
        - User or Email (Guest Email)
        - generate payment processor token (Stripe or Braintree)


3. Orders / Invoices Component
    - Connecting the Billing Profile
    - Shipping / Billing Address
    - Cart
    - Status -- Shipped? Cancelled?



4. Backup Fixtures
    python manage.py dumpdata products  --format json --indent 4 > products/fixtures/products.json

================================================
FILE: parse_git_log.py
================================================
'''
This document helps use parse our git commits so we 
can make them more easily readable and clickable
in our Readme.
'''

import os
import datetime
import git # pip install GitPython


repo = git.Repo(os.getcwd())

master = repo.head.reference

with open("parsed_log.md", "w+") as parsed_log:
	for commit in master.log():
		if "commit" in commit.message:
			commit_mess = commit.message.replace("commit: ", "").replace("commit (initial): ", "")
			line = "[{message}](../../tree/{commit}/)".format(message=commit_mess, commit=commit.newhexsha)
			parsed_log.write(line)
			parsed_log.write("\n\n")


================================================
FILE: pyvenv.cfg
================================================
home = /Library/Frameworks/Python.framework/Versions/3.8/bin
include-system-site-packages = false
version = 3.8.2


================================================
FILE: src/.gitignore
================================================
# Not Ready for Production
# marketing/

.env


ecommerce/settings/local.py
ecommerce/aws/ignore2.py

.DS_STORE
*.sublime-project
fasttracktojquery/



# Virtualenv related
bin/
include/
pip-selfcheck.json

# Django related 

# src/<yourproject>/settings/local.py
# static-cdn/  # any collected static files 


# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/

================================================
FILE: src/Procfile
================================================
web: gunicorn ecommerce.wsgi

================================================
FILE: src/accounts/__init__.py
================================================


================================================
FILE: src/accounts/admin.py
================================================
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin



from .forms import UserAdminCreationForm, UserAdminChangeForm
from .models import GuestEmail, EmailActivation

User = get_user_model()



class UserAdmin(BaseUserAdmin):
    # The forms to add and change user instances
    form = UserAdminChangeForm
    add_form = UserAdminCreationForm

    # The fields to be used in displaying the User model.
    # These override the definitions on the base UserAdmin
    # that reference specific fields on auth.User.
    list_display = ('email', 'admin')
    list_filter = ('admin', 'staff', 'is_active')
    fieldsets = (
        (None, {'fields': ('full_name', 'email', 'password')}),
       # ('Full name', {'fields': ()}),
        ('Permissions', {'fields': ('admin', 'staff', 'is_active',)}),
    )
    # add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
    # overrides get_fieldsets to use this attribute when creating a user.
    add_fieldsets = (
        (None, {
            'classes': ('wide',),
            'fields': ('email', 'password1', 'password2')}
        ),
    )
    search_fields = ('email', 'full_name',)
    ordering = ('email',)
    filter_horizontal = ()


admin.site.register(User, UserAdmin)

# Remove Group Model from admin. We're not using it.
admin.site.unregister(Group)



class EmailActivationAdmin(admin.ModelAdmin):
    search_fields = ['email']
    class Meta:
        model = EmailActivation


admin.site.register(EmailActivation, EmailActivationAdmin)


class GuestEmailAdmin(admin.ModelAdmin):
    search_fields = ['email']
    class Meta:
        model = GuestEmail


admin.site.register(GuestEmail, GuestEmailAdmin)

================================================
FILE: src/accounts/apps.py
================================================
from django.apps import AppConfig


class AccountsConfig(AppConfig):
    name = 'accounts'


================================================
FILE: src/accounts/forms.py
================================================
from django import forms
from django.contrib.auth import authenticate, login, get_user_model
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from django.core.urlresolvers import reverse
from django.utils.safestring import mark_safe

User = get_user_model()

from .models import EmailActivation, GuestEmail


class ReactivateEmailForm(forms.Form):
    email       = forms.EmailField()

    def clean_email(self):
        email = self.cleaned_data.get('email')
        qs = EmailActivation.objects.email_exists(email) 
        if not qs.exists():
            register_link = reverse("register")
            msg = """This email does not exists, would you like to <a href="{link}">register</a>?
            """.format(link=register_link)
            raise forms.ValidationError(mark_safe(msg))
        return email


class UserAdminCreationForm(forms.ModelForm):
    """A form for creating new users. Includes all the required
    fields, plus a repeated password."""
    password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
    password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)

    class Meta:
        model = User
        fields = ('full_name', 'email',) #'full_name',)

    def clean_password2(self):
        # Check that the two password entries match
        password1 = self.cleaned_data.get("password1")
        password2 = self.cleaned_data.get("password2")
        if password1 and password2 and password1 != password2:
            raise forms.ValidationError("Passwords don't match")
        return password2

    def save(self, commit=True):
        # Save the provided password in hashed format
        user = super(UserAdminCreationForm, self).save(commit=False)
        user.set_password(self.cleaned_data["password1"])
        if commit:
            user.save()
        return user



class UserDetailChangeForm(forms.ModelForm):
    full_name = forms.CharField(label='Name', required=False, widget=forms.TextInput(attrs={"class": 'form-control'}))

    class Meta:
        model = User
        fields = ['full_name']



class UserAdminChangeForm(forms.ModelForm):
    """A form for updating users. Includes all the fields on
    the user, but replaces the password field with admin's
    password hash display field.
    """
    password = ReadOnlyPasswordHashField()

    class Meta:
        model = User
        fields = ('full_name', 'email', 'password', 'is_active', 'admin')

    def clean_password(self):
        # Regardless of what the user provides, return the initial value.
        # This is done here, rather than on the field, because the
        # field does not have access to the initial value
        return self.initial["password"]



class GuestForm(forms.ModelForm):
    #email    = forms.EmailField()
    class Meta:
        model = GuestEmail
        fields = [
            'email'
        ]

    def __init__(self, request, *args, **kwargs):
        self.request = request
        super(GuestForm, self).__init__(*args, **kwargs)

    def save(self, commit=True):
        # Save the provided password in hashed format
        obj = super(GuestForm, self).save(commit=False)
        if commit:
            obj.save()
            request = self.request
            request.session['guest_email_id'] = obj.id
        return obj



class LoginForm(forms.Form):
    email    = forms.EmailField(label='Email')
    password = forms.CharField(widget=forms.PasswordInput)

    def __init__(self, request, *args, **kwargs):
        self.request = request
        super(LoginForm, self).__init__(*args, **kwargs)

    def clean(self):
        request = self.request
        data = self.cleaned_data
        email  = data.get("email")
        password  = data.get("password")
        qs = User.objects.filter(email=email)
        if qs.exists():
            # user email is registered, check active/
            not_active = qs.filter(is_active=False)
            if not_active.exists():
                ## not active, check email activation
                link = reverse("account:resend-activation")
                reconfirm_msg = """Go to <a href='{resend_link}'>
                resend confirmation email</a>.
                """.format(resend_link = link)
                confirm_email = EmailActivation.objects.filter(email=email)
                is_confirmable = confirm_email.confirmable().exists()
                if is_confirmable:
                    msg1 = "Please check your email to confirm your account or " + reconfirm_msg.lower()
                    raise forms.ValidationError(mark_safe(msg1))
                email_confirm_exists = EmailActivation.objects.email_exists(email).exists()
                if email_confirm_exists:
                    msg2 = "Email not confirmed. " + reconfirm_msg
                    raise forms.ValidationError(mark_safe(msg2))
                if not is_confirmable and not email_confirm_exists:
                    raise forms.ValidationError("This user is inactive.")
        user = authenticate(request, username=email, password=password)
        if user is None:
            raise forms.ValidationError("Invalid credentials")
        login(request, user)
        self.user = user
        return data

    # def form_valid(self, form):
    #     request = self.request
    #     next_ = request.GET.get('next')
    #     next_post = request.POST.get('next')
    #     redirect_path = next_ or next_post or None
    #     email  = form.cleaned_data.get("email")
    #     password  = form.cleaned_data.get("password")
        
    #     print(user)
    #     if user is not None:
    #         if not user.is_active:
    #             print('inactive user..')
    #             messages.success(request, "This user is inactive")
    #             return super(LoginView, self).form_invalid(form)
    #         login(request, user)
    #         user_logged_in.send(user.__class__, instance=user, request=request)
    #         try:
    #             del request.session['guest_email_id']
    #         except:
    #             pass
    #         if is_safe_url(redirect_path, request.get_host()):
    #             return redirect(redirect_path)
    #         else:
    #             return redirect("/")
    #     return super(LoginView, self).form_invalid(form)


class RegisterForm(forms.ModelForm):
    """A form for creating new users. Includes all the required
    fields, plus a repeated password."""
    password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
    password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)

    class Meta:
        model = User
        fields = ('full_name', 'email',) #'full_name',)

    def clean_password2(self):
        # Check that the two password entries match
        password1 = self.cleaned_data.get("password1")
        password2 = self.cleaned_data.get("password2")
        if password1 and password2 and password1 != password2:
            raise forms.ValidationError("Passwords don't match")
        return password2

    def save(self, commit=True):
        # Save the provided password in hashed format
        user = super(RegisterForm, self).save(commit=False)
        user.set_password(self.cleaned_data["password1"])
        user.is_active = False # send confirmation email via signals
        # obj = EmailActivation.objects.create(user=user)
        # obj.send_activation_email()
        if commit:
            user.save()
        return user





================================================
FILE: src/accounts/migrations/0001_initial.py
================================================
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-10-09 21:27
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

    initial = True

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='User',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('password', models.CharField(max_length=128, verbose_name='password')),
                ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
                ('email', models.EmailField(max_length=255, unique=True)),
                ('active', models.BooleanField(default=True)),
                ('staff', models.BooleanField(default=False)),
                ('admin', models.BooleanField(default=False)),
                ('timestamp', models.DateTimeField(auto_now_add=True)),
            ],
            options={
                'abstract': False,
            },
        ),
        migrations.CreateModel(
            name='GuestEmail',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('email', models.EmailField(max_length=254)),
                ('active', models.BooleanField(default=True)),
                ('update', models.DateTimeField(auto_now=True)),
                ('timestamp', models.DateTimeField(auto_now_add=True)),
            ],
        ),
    ]


================================================
FILE: src/accounts/migrations/0002_user_full_name.py
================================================
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-10-09 21:44
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ('accounts', '0001_initial'),
    ]

    operations = [
        migrations.AddField(
            model_name='user',
            name='full_name',
            field=models.CharField(blank=True, max_length=255, null=True),
        ),
    ]


================================================
FILE: src/accounts/migrations/0003_user_is_active.py
================================================
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-10-23 22:47
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ('accounts', '0002_user_full_name'),
    ]

    operations = [
        migrations.AddField(
            model_name='user',
            name='is_active',
            field=models.BooleanField(default=True),
        ),
    ]


================================================
FILE: src/accounts/migrations/0004_remove_user_active.py
================================================
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-10-24 17:09
from __future__ import unicode_literals

from django.db import migrations


class Migration(migrations.Migration):

    dependencies = [
        ('accounts', '0003_user_is_active'),
    ]

    operations = [
        migrations.RemoveField(
            model_name='user',
            name='active',
        ),
    ]


================================================
FILE: src/accounts/migrations/0005_emailactivation.py
================================================
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-10-24 18:13
from __future__ import unicode_literals

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

    dependencies = [
        ('accounts', '0004_remove_user_active'),
    ]

    operations = [
        migrations.CreateModel(
            name='EmailActivation',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('email', models.EmailField(max_length=254)),
                ('key', models.CharField(blank=True, max_length=120, null=True)),
                ('activated', models.BooleanField(default=False)),
                ('forced_expired', models.BooleanField(default=False)),
                ('expires', models.IntegerField(default=7)),
                ('timestamp', models.DateTimeField(auto_now_add=True)),
                ('update', models.DateTimeField(auto_now=True)),
                ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
            ],
        ),
    ]


================================================
FILE: src/accounts/migrations/__init__.py
================================================


================================================
FILE: src/accounts/models.py
================================================
from datetime import timedelta
from django.conf import settings
from django.core.urlresolvers import reverse
from django.db import models
from django.db.models import Q
from django.db.models.signals import pre_save, post_save
from django.contrib.auth.models import (
    AbstractBaseUser, BaseUserManager
)

from django.core.mail import send_mail
from django.template.loader import get_template
from django.utils import timezone

from ecommerce.utils import random_string_generator, unique_key_generator
#send_mail(subject, message, from_email, recipient_list, html_message)

DEFAULT_ACTIVATION_DAYS = getattr(settings, 'DEFAULT_ACTIVATION_DAYS', 7)

class UserManager(BaseUserManager):
    def create_user(self, email, full_name=None, password=None, is_active=True, is_staff=False, is_admin=False):
        if not email:
            raise ValueError("Users must have an email address")
        if not password:
            raise ValueError("Users must have a password")
        user_obj = self.model(
            email = self.normalize_email(email),
            full_name=full_name
        )
        user_obj.set_password(password) # change user password
        user_obj.staff = is_staff
        user_obj.admin = is_admin
        user_obj.is_active = is_active
        user_obj.save(using=self._db)
        return user_obj

    def create_staffuser(self, email,full_name=None, password=None):
        user = self.create_user(
                email,
                full_name=full_name,
                password=password,
                is_staff=True
        )
        return user

    def create_superuser(self, email, full_name=None, password=None):
        user = self.create_user(
                email,
                full_name=full_name,
                password=password,
                is_staff=True,
                is_admin=True
        )
        return user


class User(AbstractBaseUser):
    email       = models.EmailField(max_length=255, unique=True)
    full_name   = models.CharField(max_length=255, blank=True, null=True)
    is_active   = models.BooleanField(default=True) # can login 
    staff       = models.BooleanField(default=False) # staff user non superuser
    admin       = models.BooleanField(default=False) # superuser 
    timestamp   = models.DateTimeField(auto_now_add=True)
    # confirm     = models.BooleanField(default=False)
    # confirmed_date     = models.DateTimeField(default=False)

    USERNAME_FIELD = 'email' #username
    # USERNAME_FIELD and password are required by default
    REQUIRED_FIELDS = [] #['full_name'] #python manage.py createsuperuser

    objects = UserManager()

    def __str__(self):
        return self.email

    def get_full_name(self):
        if self.full_name:
            return self.full_name
        return self.email

    def get_short_name(self):
        return self.email

    def has_perm(self, perm, obj=None):
        return True

    def has_module_perms(self, app_label):
        return True

    @property
    def is_staff(self):
        if self.is_admin:
            return True
        return self.staff

    @property
    def is_admin(self):
        return self.admin

    # @property
    # def is_active(self):
    #     return self.active


class EmailActivationQuerySet(models.query.QuerySet):
    def confirmable(self):
        now = timezone.now()
        start_range = now - timedelta(days=DEFAULT_ACTIVATION_DAYS)
        # does my object have a timestamp in here
        end_range = now
        return self.filter(
                activated = False,
                forced_expired = False
              ).filter(
                timestamp__gt=start_range,
                timestamp__lte=end_range
              )


class EmailActivationManager(models.Manager):
    def get_queryset(self):
        return EmailActivationQuerySet(self.model, using=self._db)

    def confirmable(self):
        return self.get_queryset().confirmable()

    def email_exists(self, email):
        return self.get_queryset().filter(
                    Q(email=email) | 
                    Q(user__email=email)
                ).filter(
                    activated=False
                )


class EmailActivation(models.Model):
    user            = models.ForeignKey(User)
    email           = models.EmailField()
    key             = models.CharField(max_length=120, blank=True, null=True)
    activated       = models.BooleanField(default=False)
    forced_expired  = models.BooleanField(default=False)
    expires         = models.IntegerField(default=7) # 7 Days
    timestamp       = models.DateTimeField(auto_now_add=True)
    update          = models.DateTimeField(auto_now=True)

    objects = EmailActivationManager()

    def __str__(self):
        return self.email

    def can_activate(self):
        qs = EmailActivation.objects.filter(pk=self.pk).confirmable() # 1 object
        if qs.exists():
            return True
        return False

    def activate(self):
        if self.can_activate():
            # pre activation user signal
            user = self.user
            user.is_active = True
            user.save()
            # post activation signal for user
            self.activated = True
            self.save()
            return True
        return False

    def regenerate(self):
        self.key = None
        self.save()
        if self.key is not None:
            return True
        return False

    def send_activation(self):
        if not self.activated and not self.forced_expired:
            if self.key:
                base_url = getattr(settings, 'BASE_URL', 'https://www.pythonecommerce.com')
                key_path = reverse("account:email-activate", kwargs={'key': self.key}) # use reverse
                path = "{base}{path}".format(base=base_url, path=key_path)
                context = {
                    'path': path,
                    'email': self.email
                }
                txt_ = get_template("registration/emails/verify.txt").render(context)
                html_ = get_template("registration/emails/verify.html").render(context)
                subject = '1-Click Email Verification'
                from_email = settings.DEFAULT_FROM_EMAIL
                recipient_list = [self.email]
                sent_mail = send_mail(
                            subject,
                            txt_,
                            from_email,
                            recipient_list,
                            html_message=html_,
                            fail_silently=False,
                    )
                return sent_mail
        return False



def pre_save_email_activation(sender, instance, *args, **kwargs):
    if not instance.activated and not instance.forced_expired:
        if not instance.key:
            instance.key = unique_key_generator(instance)

pre_save.connect(pre_save_email_activation, sender=EmailActivation)


def post_save_user_create_reciever(sender, instance, created, *args, **kwargs):
    if created:
        obj = EmailActivation.objects.create(user=instance, email=instance.email)
        obj.send_activation()

post_save.connect(post_save_user_create_reciever, sender=User)



class GuestEmail(models.Model):
    email       = models.EmailField()
    active      = models.BooleanField(default=True)
    update      = models.DateTimeField(auto_now=True)
    timestamp   = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.email

================================================
FILE: src/accounts/passwords/__init__.py
================================================


================================================
FILE: src/accounts/passwords/urls.py
================================================
# accounts.passwords.urls.py 
from django.conf.urls import url
from django.contrib.auth import views as auth_views

urlpatterns  = [
        url(r'^password/change/$', 
                auth_views.PasswordChangeView.as_view(), 
                name='password_change'),
        url(r'^password/change/done/$',
                auth_views.PasswordChangeDoneView.as_view(), 
                name='password_change_done'),
        url(r'^password/reset/$', 
                auth_views.PasswordResetView.as_view(), 
                name='password_reset'),
        url(r'^password/reset/done/$', 
                auth_views.PasswordResetDoneView.as_view(), 
                name='password_reset_done'),
        url(r'^password/reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', 
                auth_views.PasswordResetConfirmView.as_view(), 
                name='password_reset_confirm'),
        url(r'^password/reset/complete/$', 
                auth_views.PasswordResetCompleteView.as_view(), 
                name='password_reset_complete'),
]

================================================
FILE: src/accounts/signals.py
================================================
from django.dispatch import Signal


user_logged_in = Signal(providing_args=['instance', 'request'])

================================================
FILE: src/accounts/templates/accounts/detail-update-view.html
================================================
{% extends "base.html" %}


{% block content %}
<div class='col-12 col-md-6 mx-auto'>
{% if title %}<h1 class='my-3'>{{ title }}</h1>{% endif %}
<form method='POST' action='{% if action_url %}{{ action_url }}{% endif %}'> {% csrf_token %}
    {% if next_url %}
    <input type='hidden' name='next' value='{{ next_url }}' />
    {% endif %}
  {{ form.as_p }}
  <label for='email'>Email</label>
  <input type='text' id='email' class='form-control disabled' value='{{ request.user.email }}' disabled="disabled" /><span class='help-text'>Cannot change email</span><br/>
  <button type='submit' class='btn btn-default my-3'>Save</button>
  <a href='{% url "password_change" %}'>Change Password</a>
</form>
</div>
{% endblock %}

================================================
FILE: src/accounts/templates/accounts/home.html
================================================
{% extends "base.html" %}

{% block content %}
<div class='row'>
<div class='col-12'>
<h1>Account</h1>
<hr/>
</div>
<div class='col-12 col-md-3 my-3'>
    <div class="card">
      <div class="card-body">
        <h4 class="card-title">Support</h4>
            <div class='list-group'>
                <a class='list-group-item' href='{% url "about" %}'>About</a>
                <a class='list-group-item' href='{% url "contact" %}'>Contact</a>
            </div>
      </div>
    </div>
</div>



<div class='col-12 col-md-3 my-3' id='billing'>
    <div class="card">
      <div class="card-body">
        <h4 class="card-title">Billing</h4>
            <div class='list-group'>
                <a class='list-group-item' href='{% url "orders:list" %}'>Orders</a>
                <a class='list-group-item' href='{% url "billing-payment-method" %}'>Payment Methods</a>
                <a class='list-group-item' href='{% url "addresses" %}'>Addresses</a>
                
                
            </div>
      </div>
    </div>
</div>


<div class='col-12 col-md-3 my-3'>
    <div class="card">
      <div class="card-body">
        <h4 class="card-title">Account Details</h4> 
            <div class='list-group'>
                <a class='list-group-item' href='{% url "account:user-update" %}'>Update Details</a>
                <a class='list-group-item' href='{% url "password_change" %}'>Change Password</a>
                <a class='list-group-item' href='{% url "library" %}'>Library</a>
                
            </div>

      </div>
    </div>
</div>


<div class='col-12 col-md-3 my-3'>
    <div class="card">
      <div class="card-body">
        <h4 class="card-title">Preferences</h4> 
            <div class='list-group'>
                <a class='list-group-item' href='{% url "marketing-pref" %}'>Email Marketing</a>
                
            </div>

      </div>
    </div>
</div>


<div class='col-12 col-md-3 my-3'>
    <div class="card">
      <div class="card-body">
        <h4 class="card-title">History</h4> 
              <div class='list-group'>
                <a class='list-group-item' href='{% url "account:user-product-history" %}'>Products</a>
            </div>
      </div>
    </div>
</div>


</div>


{% endblock %}

================================================
FILE: src/accounts/templates/accounts/login.html
================================================
{% extends "base.html" %}

{% block content %}
<h1>Login</h1>
    <form method='POST'> {% csrf_token %}
      {{ form }}
      <button type='submit' class='btn btn-default'>Submit</button>
    </form>

{% endblock %}

================================================
FILE: src/accounts/templates/accounts/register.html
================================================
{% extends "base.html" %}

{% block content %}
    <h1>Register</h1>
    <form method='POST'> {% csrf_token %}
      {{ form }}
      <button type='submit' class='btn btn-default'>Submit</button>
    </form>

{% endblock %}

================================================
FILE: src/accounts/templates/accounts/snippets/form.html
================================================
<form method='POST' action='{% if action_url %}{{ action_url }}{% else %}{% url "login" %}{% endif %}'> {% csrf_token %}
    {% if next_url %}
    <input type='hidden' name='next' value='{{ next_url }}' />
    {% endif %}
  {{ form }}
  <button type='submit' class='btn btn-default'>Submit</button>
</form>

================================================
FILE: src/accounts/tests.py
================================================
from django.test import TestCase

# Create your tests here.


================================================
FILE: src/accounts/urls.py
================================================
from django.conf.urls import url

from products.views import UserProductHistoryView
from .views import (
        AccountHomeView, 
        AccountEmailActivateView,
        UserDetailUpdateView
        )

urlpatterns = [
    url(r'^$', AccountHomeView.as_view(), name='home'),
    url(r'^details/$', UserDetailUpdateView.as_view(), name='user-update'),
    url(r'history/products/$', UserProductHistoryView.as_view(), name='user-product-history'),
    url(r'^email/confirm/(?P<key>[0-9A-Za-z]+)/$', 
            AccountEmailActivateView.as_view(), 
            name='email-activate'),
    url(r'^email/resend-activation/$', 
            AccountEmailActivateView.as_view(), 
            name='resend-activation'),
]

# account/email/confirm/asdfads/ -> activation view

================================================
FILE: src/accounts/views.py
================================================
from django.contrib.auth import authenticate, login, get_user_model
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib import messages
from django.core.urlresolvers import reverse
from django.utils.decorators import method_decorator
from django.views.generic import CreateView, FormView, DetailView, View, UpdateView
from django.views.generic.edit import FormMixin
from django.http import HttpResponse
from django.shortcuts import render,redirect
from django.utils.http import is_safe_url
from django.utils.safestring import mark_safe

from ecommerce.mixins import NextUrlMixin, RequestFormAttachMixin
from .forms import LoginForm, RegisterForm, GuestForm, ReactivateEmailForm, UserDetailChangeForm
from .models import GuestEmail, EmailActivation
from .signals import user_logged_in


# @login_required # /accounts/login/?next=/some/path/
# def account_home_view(request):
#     return render(request, "accounts/home.html", {})


#LoginRequiredMixin,
class AccountHomeView(LoginRequiredMixin, DetailView):
    template_name = 'accounts/home.html'
    def get_object(self):
        return self.request.user



class AccountEmailActivateView(FormMixin, View):
    success_url = '/login/'
    form_class = ReactivateEmailForm
    key = None
    def get(self, request, key=None, *args, **kwargs):
        self.key = key
        if key is not None:
            qs = EmailActivation.objects.filter(key__iexact=key)
            confirm_qs = qs.confirmable()
            if confirm_qs.count() == 1:
                obj = confirm_qs.first()
                obj.activate()
                messages.success(request, "Your email has been confirmed. Please login.")
                return redirect("login")
            else:
                activated_qs = qs.filter(activated=True)
                if activated_qs.exists():
                    reset_link = reverse("password_reset")
                    msg = """Your email has already been confirmed
                    Do you need to <a href="{link}">reset your password</a>?
                    """.format(link=reset_link)
                    messages.success(request, mark_safe(msg))
                    return redirect("login") 
        context = {'form': self.get_form(),'key': key}
        return render(request, 'registration/activation-error.html', context)

    def post(self, request, *args, **kwargs):
        # create form to receive an email
        form = self.get_form()
        if form.is_valid():
            return self.form_valid(form)
        else:
            return self.form_invalid(form)

    def form_valid(self, form):
        msg = """Activation link sent, please check your email."""
        request = self.request
        messages.success(request, msg)
        email = form.cleaned_data.get("email")
        obj = EmailActivation.objects.email_exists(email).first()
        user = obj.user 
        new_activation = EmailActivation.objects.create(user=user, email=email)
        new_activation.send_activation()
        return super(AccountEmailActivateView, self).form_valid(form)

    def form_invalid(self, form):
        context = {'form': form, "key": self.key }
        return render(self.request, 'registration/activation-error.html', context)


class GuestRegisterView(NextUrlMixin,  RequestFormAttachMixin, CreateView):
    form_class = GuestForm
    default_next = '/register/'

    def get_success_url(self):
        return self.get_next_url()

    def form_invalid(self, form):
        return redirect(self.default_next)


class LoginView(NextUrlMixin, RequestFormAttachMixin, FormView):
    form_class = LoginForm
    success_url = '/'
    template_name = 'accounts/login.html'
    default_next = '/'

    def form_valid(self, form):
        next_path = self.get_next_url()
        return redirect(next_path)




class RegisterView(CreateView):
    form_class = RegisterForm
    template_name = 'accounts/register.html'
    success_url = '/login/'




class UserDetailUpdateView(LoginRequiredMixin, UpdateView):
    form_class = UserDetailChangeForm
    template_name = 'accounts/detail-update-view.html'

    def get_object(self):
        return self.request.user

    def get_context_data(self, *args, **kwargs):
        context = super(UserDetailUpdateView, self).get_context_data(*args, **kwargs)
        context['title'] = 'Change Your Account Details'
        return context

    def get_success_url(self):
        return reverse("account:home")


# def login_page(request):
#     form = LoginForm(request.POST or None)
#     context = {
#         "form": form
#     }
#     next_ = request.GET.get('next')
#     next_post = request.POST.get('next')
#     redirect_path = next_ or next_post or None
#     if form.is_valid():
#         username  = form.cleaned_data.get("username")
#         password  = form.cleaned_data.get("password")
#         user = authenticate(request, username=username, password=password)
#         if user is not None:
#             login(request, user)
#             try:
#                 del request.session['guest_email_id']
#             except:
#                 pass
#             if is_safe_url(redirect_path, request.get_host()):
#                 return redirect(redirect_path)
#             else:
#                 return redirect("/")
#         else:
#             # Return an 'invalid login' error message.
#             print("Error")
#     return render(request, "accounts/login.html", context)

# User = get_user_model()
# def register_page(request):
#     form = RegisterForm(request.POST or None)
#     context = {
#         "form": form
#     }
#     if form.is_valid():
#         form.save()
#     return render(request, "accounts/register.html", context)

================================================
FILE: src/addresses/__init__.py
================================================


================================================
FILE: src/addresses/admin.py
================================================
from django.contrib import admin

from .models import Address

admin.site.register(Address)

================================================
FILE: src/addresses/apps.py
================================================
from django.apps import AppConfig


class AddressesConfig(AppConfig):
    name = 'addresses'


================================================
FILE: src/addresses/forms.py
================================================
from django import forms

from .models import Address


class AddressForm(forms.ModelForm):
    """
    User-related CRUD form
    """
    class Meta:
        model = Address
        fields = [
            'nickname',
            'name',
            #'billing_profile',
            'address_type',
            'address_line_1',
            'address_line_2',
            'city',
            'country',
            'state',
            'postal_code'
        ]




class AddressCheckoutForm(forms.ModelForm):
    """
    User-related checkout address create form
    """
    class Meta:
        model = Address
        fields = [
            'nickname',
            'name',
            #'billing_profile',
            #'address_type',
            'address_line_1',
            'address_line_2',
            'city',
            'country',
            'state',
            'postal_code'
        ]



================================================
FILE: src/addresses/migrations/0001_initial.py
================================================
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-09-28 23:42
from __future__ import unicode_literals

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

    initial = True

    dependencies = [
        ('billing', '0002_auto_20170928_2052'),
    ]

    operations = [
        migrations.CreateModel(
            name='Address',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('address_type', models.CharField(choices=[('billing', 'Billing'), ('shipping', 'Shipping')], max_length=120)),
                ('address_line_1', models.CharField(max_length=120)),
                ('address_line_2', models.CharField(blank=True, max_length=120, null=True)),
                ('city', models.CharField(max_length=120)),
                ('country', models.CharField(default='United States of America', max_length=120)),
                ('state', models.CharField(max_length=120)),
                ('postal_code', models.CharField(max_length=120)),
                ('billing_profile', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='billing.BillingProfile')),
            ],
        ),
    ]


================================================
FILE: src/addresses/migrations/0002_auto_20171107_0055.py
================================================
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-11-07 00:55
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ('addresses', '0001_initial'),
    ]

    operations = [
        migrations.AddField(
            model_name='address',
            name='name',
            field=models.CharField(blank=True, help_text='Shipping to? Who is it for?', max_length=120, null=True),
        ),
        migrations.AddField(
            model_name='address',
            name='nickname',
            field=models.CharField(blank=True, help_text='Internal Reference Nickname', max_length=120, null=True),
        ),
        migrations.AlterField(
            model_name='address',
            name='address_type',
            field=models.CharField(choices=[('billing', 'Billing address'), ('shipping', 'Shipping address')], max_length=120),
        ),
    ]


================================================
FILE: src/addresses/migrations/__init__.py
================================================


================================================
FILE: src/addresses/models.py
================================================
from django.db import models
from django.core.urlresolvers import reverse
from billing.models import BillingProfile

ADDRESS_TYPES = (
    ('billing', 'Billing address'),
    ('shipping', 'Shipping address'),
)

class Address(models.Model):
    billing_profile = models.ForeignKey(BillingProfile)
    name            = models.CharField(max_length=120, null=True, blank=True, help_text='Shipping to? Who is it for?')
    nickname        = models.CharField(max_length=120, null=True, blank=True, help_text='Internal Reference Nickname')
    address_type    = models.CharField(max_length=120, choices=ADDRESS_TYPES)
    address_line_1  = models.CharField(max_length=120)
    address_line_2  = models.CharField(max_length=120, null=True, blank=True)
    city            = models.CharField(max_length=120)
    country         = models.CharField(max_length=120, default='United States of America')
    state           = models.CharField(max_length=120)
    postal_code     = models.CharField(max_length=120)

    def __str__(self):
        if self.nickname:
            return str(self.nickname)
        return str(self.address_line_1)

    def get_absolute_url(self):
        return reverse("address-update", kwargs={"pk": self.pk})

    def get_short_address(self):
        for_name = self.name 
        if self.nickname:
            for_name = "{} | {},".format( self.nickname, for_name)
        return "{for_name} {line1}, {city}".format(
                for_name = for_name or "",
                line1 = self.address_line_1,
                city = self.city
            ) 

    def get_address(self):
        return "{for_name}\n{line1}\n{line2}\n{city}\n{state}, {postal}\n{country}".format(
                for_name = self.name or "",
                line1 = self.address_line_1,
                line2 = self.address_line_2 or "",
                city = self.city,
                state = self.state,
                postal= self.postal_code,
                country = self.country
            )

================================================
FILE: src/addresses/templates/addresses/form.html
================================================
<form method='POST' action='{% if action_url %}{{ action_url }}{% else %}{% url "login" %}{% endif %}'> {% csrf_token %}
    {% if next_url %}
    <input type='hidden' name='next' value='{{ next_url }}' />
    {% endif %}

    {% if address_type %}
    <input type='hidden' name='address_type' value='{{ address_type }}' />
    {% endif %}
  {{ form.as_p }}
  <button type='submit' class='btn btn-default'>Submit</button>
</form>

================================================
FILE: src/addresses/templates/addresses/list.html
================================================
{% extends "base.html" %}

{% block content %}
<div class='row'>
<div class='col-12'>
<h1>Address{% if object_list.count > 1%}es{% endif %} <small><a href='{% url "address-create" %}'>Create New</a></small></h1>
<hr/>
</div>
</div>
<div class='row'>
        {% for obj in object_list %}
            <div class='col-12 col-md-3 my-3'>
                <div class="card">
                  <div class="card-body">
                    <h4 class="card-title">{{ obj }}</h4> 
                     <small>{{ obj.get_address_type_display }}</small><br/>
                     <br/>
                     <h5>Address</h5>
                     {{ obj.get_address|linebreaks }}
                    
                    <a href='{{ obj.get_absolute_url }}' class='btn btn-default'>Edit</a>
                  </div>
                </div>
            </div>
        {% empty %}
         <p class='lead text-center'><a href='{% url "address-create" %}'>Create New</a></p>
        {% endfor %}
</div>
{% endblock %}

================================================
FILE: src/addresses/templates/addresses/prev_addresses.html
================================================
{% if address_qs.exists %}
        <form method='POST' action='{{ action_url }}'> {% csrf_token %}
             {% if next_url %}
            <input type='hidden' name='next' value='{{ next_url }}' />
            {% endif %}
            {% if address_type %}
            <input type='hidden' name='address_type' value='{{ address_type }}' />
            {% endif %}


            {% for address in address_qs %}
                <label for='address-{{ address.id }}'>
                    <input id='address-{{ address.id }}' type='radio' name='shipping_address' value='{{ address.id }}' />
                {{ address.get_short_address }}
                </label><br/>
            {% endfor %}
            <button type='submit' class='btn btn-success'>Use Address</button>
        </form>
{% endif %}

================================================
FILE: src/addresses/templates/addresses/update.html
================================================
{% extends "base.html" %}

{% block content %}

<div class='row'>
    <div class='col-10 mx-auto col-md-6 '>
        {% if form.instance.address_line_1  %}
        <h3 class='my-5'>Update Address</h3>
        {% else %}
        <h3 class='my-5'>Create Address</h3>
        {% endif %}
        <hr>
    <form method='POST' action=''> {% csrf_token %}
      {{ form.as_p }}
      <button type='submit' class='btn btn-default'>Save Address</button>
    </form>
    </div>

</div>

{% endblock %}

================================================
FILE: src/addresses/tests.py
================================================
from django.test import TestCase

# Create your tests here.


================================================
FILE: src/addresses/views.py
================================================
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import ListView, UpdateView, CreateView
from django.shortcuts import render, redirect
from django.utils.http import is_safe_url
# CRUD create update retrieve delete

from billing.models import BillingProfile
from .forms import AddressCheckoutForm, AddressForm
from .models import Address



class AddressListView(LoginRequiredMixin, ListView):
    template_name = 'addresses/list.html'

    def get_queryset(self):
        request = self.request
        billing_profile, billing_profile_created = BillingProfile.objects.new_or_get(request)
        return Address.objects.filter(billing_profile=billing_profile)



class AddressUpdateView(LoginRequiredMixin, UpdateView):
    template_name = 'addresses/update.html'
    form_class = AddressForm
    success_url = '/addresses'
    
    def get_queryset(self):
        request = self.request
        billing_profile, billing_profile_created = BillingProfile.objects.new_or_get(request)
        return Address.objects.filter(billing_profile=billing_profile)


class AddressCreateView(LoginRequiredMixin, CreateView):
    template_name = 'addresses/update.html'
    form_class = AddressForm
    success_url = '/addresses'

    def form_valid(self, form):
        request = self.request
        billing_profile, billing_profile_created = BillingProfile.objects.new_or_get(request)
        instance = form.save(commit=False)
        instance.billing_profile = billing_profile
        instance.save()
        return super(AddressCreateView, self).form_valid(form)

    # def get_queryset(self):
        
    #     return Address.objects.filter(billing_profile=billing_profile)






def checkout_address_create_view(request):
    form = AddressCheckoutForm(request.POST or None)
    context = {
        "form": form
    }
    next_ = request.GET.get('next')
    next_post = request.POST.get('next')
    redirect_path = next_ or next_post or None
    if form.is_valid():
        print(request.POST)
        instance = form.save(commit=False)
        billing_profile, billing_profile_created = BillingProfile.objects.new_or_get(request)
        if billing_profile is not None:
            address_type = request.POST.get('address_type', 'shipping')
            instance.billing_profile = billing_profile
            instance.address_type = address_type
            instance.save()
            request.session[address_type + "_address_id"] = instance.id
            print(address_type + "_address_id")
        else:
            print("Error here")
            return redirect("cart:checkout")

        if is_safe_url(redirect_path, request.get_host()):
            return redirect(redirect_path)
    return redirect("cart:checkout") 


def checkout_address_reuse_view(request):
    if request.user.is_authenticated():
        context = {}
        next_ = request.GET.get('next')
        next_post = request.POST.get('next')
        redirect_path = next_ or next_post or None
        if request.method == "POST":
            print(request.POST)
            shipping_address = request.POST.get('shipping_address', None)
            address_type = request.POST.get('address_type', 'shipping')
            billing_profile, billing_profile_created = BillingProfile.objects.new_or_get(request)
            if shipping_address is not None:
                qs = Address.objects.filter(billing_profile=billing_profile, id=shipping_address)
                if qs.exists():
                    request.session[address_type + "_address_id"] = shipping_address
                if is_safe_url(redirect_path, request.get_host()):
                    return redirect(redirect_path)
    return redirect("cart:checkout") 



================================================
FILE: src/analytics/__init__.py
================================================


================================================
FILE: src/analytics/admin.py
================================================
from django.contrib import admin

from .models import ObjectViewed, UserSession


admin.site.register(ObjectViewed)

admin.site.register(UserSession)

================================================
FILE: src/analytics/apps.py
================================================
from django.apps import AppConfig


class AnalyticsConfig(AppConfig):
    name = 'analytics'


================================================
FILE: src/analytics/migrations/0001_initial.py
================================================
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-10-10 21:30
from __future__ import unicode_literals

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),
        ('contenttypes', '0002_remove_content_type_name'),
    ]

    operations = [
        migrations.CreateModel(
            name='ObjectViewed',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('ip_address', models.CharField(blank=True, max_length=220, null=True)),
                ('object_id', models.PositiveIntegerField()),
                ('timestamp', models.DateTimeField(auto_now_add=True)),
                ('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType')),
                ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
            ],
            options={
                'verbose_name': 'Object viewed',
                'verbose_name_plural': 'Objects viewed',
                'ordering': ['-timestamp'],
            },
        ),
    ]


================================================
FILE: src/analytics/migrations/0002_usersession.py
================================================
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-10-10 22:08
from __future__ import unicode_literals

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

    dependencies = [
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
        ('analytics', '0001_initial'),
    ]

    operations = [
        migrations.CreateModel(
            name='UserSession',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('ip_address', models.CharField(blank=True, max_length=220, null=True)),
                ('session_key', models.CharField(blank=True, max_length=100, null=True)),
                ('timestamp', models.DateTimeField(auto_now_add=True)),
                ('active', models.BooleanField(default=True)),
                ('ended', models.BooleanField(default=False)),
                ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
            ],
        ),
    ]


================================================
FILE: src/analytics/migrations/__init__.py
================================================


================================================
FILE: src/analytics/mixins.py
================================================
from .signals import object_viewed_signal


class ObjectViewedMixin(object):
    def get_context_data(self, *args, **kwargs):
        context = super(ObjectViewedMixin, self).get_context_data(*args, **kwargs)
        request = self.request
        instance  = context.get('object')
        if instance:
            object_viewed_signal.send(instance.__class__, instance=instance, request=request)
        return context

================================================
FILE: src/analytics/models.py
================================================
from django.conf import settings
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.contrib.sessions.models import Session
from django.db import models
from django.db.models.signals import pre_save, post_save

from accounts.signals import user_logged_in
from .signals import object_viewed_signal
from .utils import get_client_ip

User = settings.AUTH_USER_MODEL


FORCE_SESSION_TO_ONE = getattr(settings, 'FORCE_SESSION_TO_ONE', False)
FORCE_INACTIVE_USER_ENDSESSION= getattr(settings, 'FORCE_INACTIVE_USER_ENDSESSION', False)


class ObjectViewedQuerySet(models.query.QuerySet):
    def by_model(self, model_class, model_queryset=False):
        c_type = ContentType.objects.get_for_model(model_class)
        qs = self.filter(content_type=c_type)
        if model_queryset:
            viewed_ids = [x.object_id for x in qs]
            return model_class.objects.filter(pk__in=viewed_ids)
        return qs

class ObjectViewedManager(models.Manager):
    def get_queryset(self):
        return ObjectViewedQuerySet(self.model, using=self._db)

    def by_model(self, model_class, model_queryset=False):
        return self.get_queryset().by_model(model_class, model_queryset=model_queryset)
    
class ObjectViewed(models.Model):
    user                = models.ForeignKey(User, blank=True, null=True) # User instance instance.id
    ip_address          = models.CharField(max_length=220, blank=True, null=True) #IP Field
    content_type        = models.ForeignKey(ContentType) # User, Product, Order, Cart, Address
    object_id           = models.PositiveIntegerField() # User id, Product id, Order id,
    content_object      = GenericForeignKey('content_type', 'object_id') # Product instance
    timestamp           = models.DateTimeField(auto_now_add=True)

    objects = ObjectViewedManager()

    def __str__(self):
        return "%s viewed on %s" %(self.content_object, self.timestamp)

    class Meta:
        ordering = ['-timestamp'] # most recent saved show up first
        verbose_name = 'Object viewed'
        verbose_name_plural = 'Objects viewed'


def object_viewed_receiver(sender, instance, request, *args, **kwargs):
    c_type = ContentType.objects.get_for_model(sender) # instance.__class__
    user = None
    if request.user.is_authenticated():
        user = request.user
    new_view_obj = ObjectViewed.objects.create(
                user = user,
                content_type=c_type,
                object_id=instance.id,
                ip_address = get_client_ip(request)
        )


object_viewed_signal.connect(object_viewed_receiver)





class UserSession(models.Model):
    user                = models.ForeignKey(User, blank=True, null=True) # User instance instance.id
    ip_address          = models.CharField(max_length=220, blank=True, null=True) #IP Field
    session_key         = models.CharField(max_length=100, blank=True, null=True) #min 50
    timestamp           = models.DateTimeField(auto_now_add=True)
    active              = models.BooleanField(default=True)
    ended               = models.BooleanField(default=False)

    def end_session(self):
        session_key = self.session_key
        ended = self.ended
        try:
            Session.objects.get(pk=session_key).delete()
            self.active = False
            self.ended = True
            self.save()
        except:
            pass
        return self.ended



def post_save_session_receiver(sender, instance, created, *args, **kwargs):
    if created:
        qs = UserSession.objects.filter(user=instance.user, ended=False, active=False).exclude(id=instance.id)
        for i in qs:
            i.end_session()
    if not instance.active and not instance.ended:
        instance.end_session()

if FORCE_SESSION_TO_ONE:
    post_save.connect(post_save_session_receiver, sender=UserSession)


def post_save_user_changed_receiver(sender, instance, created, *args, **kwargs):
    if not created:
        if instance.is_active == False:
            qs = UserSession.objects.filter(user=instance.user, ended=False, active=False)
            for i in qs:
                i.end_session()


if FORCE_INACTIVE_USER_ENDSESSION:
    post_save.connect(post_save_user_changed_receiver, sender=User)



def user_logged_in_receiver(sender, instance, request, *args, **kwargs):
    user = instance
    ip_address = get_client_ip(request)
    session_key = request.session.session_key # Django 1.11
    UserSession.objects.create(
            user=user,
            ip_address=ip_address,
            session_key=session_key
        )


user_logged_in.connect(user_logged_in_receiver)





================================================
FILE: src/analytics/signals.py
================================================
from django.dispatch import Signal


object_viewed_signal = Signal(providing_args=['instance', 'request'])

================================================
FILE: src/analytics/templates/analytics/sales.html
================================================
{% extends "base.html" %}


{% block content %}


<div class='row my-5'>
    <div class='col-12'>
        <h1>Sales Data</h1>
    </div>
</div>

<hr/>

<div class='row my-5'>
    <div class='col-4'>
        <h3>Today's sales</h3>
        <hr/>
        <p>Recent Total: ${{ today.recent_data.total__sum }}</p>
        <ul>
        {% for order in today.recent|slice:":5" %}
            <li class='my-3'>Order #{{ order.order_id }}<br/>
            ${{ order.total }}<br/>
            {{ order.updated|timesince }} ago</li>
        {% endfor %}
    </ul>
   
    <h3>This week's sales</h3>
    <hr/>
        <p>Recent Total: ${{ this_week.recent_data.total__sum }}</p>
        <ul>
        {% for order in this_week.recent|slice:":5" %}
            <li class='my-3'>Order #{{ order.order_id }}<br/>
            ${{ order.total }}<br/>
            {{ order.updated|timesince }} ago</li>
        {% endfor %}
    </ul>
    </div>

    <div class='col'>
       <canvas class='cfe-render-chart' id="thisWeekSales" data-type='week' width="400" height="400"></canvas>
    </div>
</div>



<hr/>

<div class='row my-5'>
    <div class='col-12'>
        <h1>Previous 4 weeks</h1>
    </div>
    <div class='col'>
        <p>Orders Total: ${{ last_four_weeks.recent_data.total__sum }}</p>
        <p>Shipped Total: {% if last_four_weeks.shipped_data.total__sum %}${{ last_four_weeks.shipped_data.total__sum }} {% endif %}</p>
        <p>Paid Totals: ${{ last_four_weeks.paid_data.total__sum }}</p>

    </div>
     <div class='col'>
       <canvas class='cfe-render-chart' id="fourWeekSales" data-type='4weeks' width="400" height="400"></canvas>
    </div>
</div>





{% endblock %}

================================================
FILE: src/analytics/tests.py
================================================
from django.test import TestCase

# Create your tests here.


================================================
FILE: src/analytics/utils.py
================================================


def get_client_ip(request):
    x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
    if x_forwarded_for:
        ip = x_forwarded_for.split(",")[0]
    else:
        ip = request.META.get("REMOTE_ADDR", None)
    return ip

================================================
FILE: src/analytics/views.py
================================================
import random
import datetime
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db.models import Count, Sum, Avg
from django.http import HttpResponse, JsonResponse
from django.views.generic import TemplateView, View
from django.shortcuts import render

from django.utils import  timezone


from orders.models import Order

class SalesAjaxView(View):
    def get(self, request, *args, **kwargs):
        data = {}
        if request.user.is_staff:
            qs = Order.objects.all().by_weeks_range(weeks_ago=5, number_of_weeks=5)
            if request.GET.get('type') == 'week':
                days = 7
                start_date = timezone.now().today() - datetime.timedelta(days=days-1)
                datetime_list = []
                labels = []
                salesItems = []
                for x in range(0, days):
                    new_time = start_date + datetime.timedelta(days=x)
                    datetime_list.append(
                            new_time
                        )
                    labels.append(
                        new_time.strftime("%a") # mon
                    )
                    new_qs = qs.filter(updated__day=new_time.day, updated__month=new_time.month)
                    day_total = new_qs.totals_data()['total__sum'] or 0
                    salesItems.append(
                        day_total
                    )
                #print(datetime_list)

                data['labels'] = labels
                data['data'] = salesItems
            if request.GET.get('type') == '4weeks':
                data['labels'] = ["Four Weeks Ago", "Three Weeks Ago", "Two Weeks Ago", "Last Week", "This Week"]
                current = 5
                data['data'] = []
                for i in range(0, 5):
                    new_qs = qs.by_weeks_range(weeks_ago=current, number_of_weeks=1)
                    sales_total = new_qs.totals_data()['total__sum'] or 0
                    data['data'].append(sales_total)
                    current -= 1
        return JsonResponse(data)



class SalesView(LoginRequiredMixin, TemplateView):
    template_name = 'analytics/sales.html'

    def dispatch(self, *args, **kwargs):
        user = self.request.user
        if not user.is_staff:
            return render(self.request, "400.html", {})
        return super(SalesView, self).dispatch(*args, **kwargs)


    def get_context_data(self, *args, **kwargs):
        context = super(SalesView, self).get_context_data(*args, **kwargs)
        qs = Order.objects.all().by_weeks_range(weeks_ago=10, number_of_weeks=10)
        start_date = timezone.now().date() - datetime.timedelta(hours=24)
        end_date = timezone.now().date() + datetime.timedelta(hours=12)
        today_data = qs.by_range(start_date=start_date, end_date=end_date).get_sales_breakdown()
        context['today'] = today_data
        context['this_week'] = qs.by_weeks_range(weeks_ago=1, number_of_weeks=1).get_sales_breakdown()
        context['last_four_weeks'] = qs.by_weeks_range(weeks_ago=5, number_of_weeks=4).get_sales_breakdown()
        return context

================================================
FILE: src/billing/__init__.py
================================================


================================================
FILE: src/billing/admin.py
================================================
from django.contrib import admin

from .models import BillingProfile, Card, Charge

admin.site.register(BillingProfile)

admin.site.register(Card)

admin.site.register(Charge)

================================================
FILE: src/billing/apps.py
================================================
from django.apps import AppConfig


class BillingConfig(AppConfig):
    name = 'billing'


================================================
FILE: src/billing/migrations/0001_initial.py
================================================
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-09-28 20:50
from __future__ import unicode_literals

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='BillingProfile',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('email', models.EmailField(max_length=254)),
                ('active', models.BooleanField(default=True)),
                ('update', models.DateTimeField(auto_now=True)),
                ('timestamp', models.DateTimeField(auto_now_add=True)),
                ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, unique=True)),
            ],
        ),
    ]


================================================
FILE: src/billing/migrations/0002_auto_20170928_2052.py
================================================
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-09-28 20:52
from __future__ import unicode_literals

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

    dependencies = [
        ('billing', '0001_initial'),
    ]

    operations = [
        migrations.AlterField(
            model_name='billingprofile',
            name='user',
            field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
        ),
    ]


================================================
FILE: src/billing/migrations/0003_billingprofile_customer_id.py
================================================
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-10-11 19:13
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ('billing', '0002_auto_20170928_2052'),
    ]

    operations = [
        migrations.AddField(
            model_name='billingprofile',
            name='customer_id',
            field=models.CharField(blank=True, max_length=120, null=True),
        ),
    ]


================================================
FILE: src/billing/migrations/0004_card.py
================================================
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-10-11 22:08
from __future__ import unicode_literals

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

    dependencies = [
        ('billing', '0003_billingprofile_customer_id'),
    ]

    operations = [
        migrations.CreateModel(
            name='Card',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('stripe_id', models.CharField(max_length=120)),
                ('brand', models.CharField(blank=True, max_length=120, null=True)),
                ('country', models.CharField(blank=True, max_length=20, null=True)),
                ('exp_month', models.IntegerField(blank=True, null=True)),
                ('exp_year', models.IntegerField(blank=True, null=True)),
                ('last4', models.CharField(blank=True, max_length=4, null=True)),
                ('billing_profile', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='billing.BillingProfile')),
            ],
        ),
    ]


================================================
FILE: src/billing/migrations/0005_card_default.py
================================================
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-10-11 22:10
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ('billing', '0004_card'),
    ]

    operations = [
        migrations.AddField(
            model_name='card',
            name='default',
            field=models.BooleanField(default=True),
        ),
    ]


================================================
FILE: src/billing/migrations/0006_charge.py
================================================
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-10-12 00:06
from __future__ import unicode_literals

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

    dependencies = [
        ('billing', '0005_card_default'),
    ]

    operations = [
        migrations.CreateModel(
            name='Charge',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('stripe_id', models.CharField(max_length=120)),
                ('paid', models.BooleanField(default=False)),
                ('refunded', models.BooleanField(default=False)),
                ('outcome', models.TextField(blank=True, null=True)),
                ('outcome_type', models.CharField(blank=True, max_length=120, null=True)),
                ('seller_message', models.CharField(blank=True, max_length=120, null=True)),
                ('risk_level', models.CharField(blank=True, max_length=120, null=True)),
                ('billing_profile', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='billing.BillingProfile')),
            ],
        ),
    ]


================================================
FILE: src/billing/migrations/0007_auto_20171012_1935.py
================================================
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-10-12 19:35
from __future__ import unicode_literals

from django.db import migrations, models
import django.utils.timezone


class Migration(migrations.Migration):

    dependencies = [
        ('billing', '0006_charge'),
    ]

    operations = [
        migrations.AddField(
            model_name='card',
            name='active',
            field=models.BooleanField(default=True),
        ),
        migrations.AddField(
            model_name='card',
            name='timestamp',
            field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
            preserve_default=False,
        ),
    ]


================================================
FILE: src/billing/migrations/__init__.py
================================================


================================================
FILE: src/billing/models.py
================================================
from django.conf import settings
from django.db import models
from django.db.models.signals import post_save, pre_save
from django.core.urlresolvers import reverse
from accounts.models import GuestEmail
User = settings.AUTH_USER_MODEL

# abc@teamcfe.com -->> 1000000 billing profiles
# user abc@teamcfe.com -- 1 billing profile

import stripe
STRIPE_SECRET_KEY = getattr(settings, "STRIPE_SECRET_KEY", "sk_test_cu1lQmcg1OLffhLvYrSCp5XE")
stripe.api_key = STRIPE_SECRET_KEY



class BillingProfileManager(models.Manager):
    def new_or_get(self, request):
        user = request.user
        guest_email_id = request.session.get('guest_email_id')
        created = False
        obj = None
        if user.is_authenticated():
            'logged in user checkout; remember payment stuff'
            obj, created = self.model.objects.get_or_create(
                            user=user, email=user.email)
        elif guest_email_id is not None:
            'guest user checkout; auto reloads payment stuff'
            guest_email_obj = GuestEmail.objects.get(id=guest_email_id)
            obj, created = self.model.objects.get_or_create(
                                            email=guest_email_obj.email)
        else:
            pass
        return obj, created

class BillingProfile(models.Model):
    user        = models.OneToOneField(User, null=True, blank=True)
    email       = models.EmailField()
    active      = models.BooleanField(default=True)
    update      = models.DateTimeField(auto_now=True)
    timestamp   = models.DateTimeField(auto_now_add=True)
    customer_id = models.CharField(max_length=120, null=True, blank=True)
    # customer_id in Stripe or Braintree

    objects = BillingProfileManager()

    def __str__(self):
        return self.email

    def charge(self, order_obj, card=None):
        return Charge.objects.do(self, order_obj, card)

    def get_cards(self):
        return self.card_set.all()

    def get_payment_method_url(self):
        return reverse('billing-payment-method')

    @property
    def has_card(self): # instance.has_card
        card_qs = self.get_cards()
        return card_qs.exists() # True or False

    @property
    def default_card(self):
        default_cards = self.get_cards().filter(active=True, default=True)
        if default_cards.exists():
            return default_cards.first()
        return None

    def set_cards_inactive(self):
        cards_qs = self.get_cards()
        cards_qs.update(active=False)
        return cards_qs.filter(active=True).count()

def billing_profile_created_receiver(sender, instance, *args, **kwargs):
    if not instance.customer_id and instance.email:
        print("ACTUAL API REQUEST Send to stripe/braintree")
        customer = stripe.Customer.create(
                email = instance.email
            )
        print(customer)
        instance.customer_id = customer.id

pre_save.connect(billing_profile_created_receiver, sender=BillingProfile)


def user_created_receiver(sender, instance, created, *args, **kwargs):
    if created and instance.email:
        BillingProfile.objects.get_or_create(user=instance, email=instance.email)

post_save.connect(user_created_receiver, sender=User)


class CardManager(models.Manager):
    def all(self, *args, **kwargs): # ModelKlass.objects.all() --> ModelKlass.objects.filter(active=True)
        return self.get_queryset().filter(active=True)

    def add_new(self, billing_profile, token):
        if token:
            customer = stripe.Customer.retrieve(billing_profile.customer_id)
            stripe_card_response = customer.sources.create(source=token)
            new_card = self.model(
                    billing_profile=billing_profile,
                    stripe_id = stripe_card_response.id,
                    brand = stripe_card_response.brand,
                    country = stripe_card_response.country,
                    exp_month = stripe_card_response.exp_month,
                    exp_year = stripe_card_response.exp_year,
                    last4 = stripe_card_response.last4
                )
            new_card.save()
            return new_card
        return None


class Card(models.Model):
    billing_profile         = models.ForeignKey(BillingProfile)
    stripe_id               = models.CharField(max_length=120)
    brand                   = models.CharField(max_length=120, null=True, blank=True)
    country                 = models.CharField(max_length=20, null=True, blank=True)
    exp_month               = models.IntegerField(null=True, blank=True)
    exp_year                = models.IntegerField(null=True, blank=True)
    last4                   = models.CharField(max_length=4, null=True, blank=True)
    default                 = models.BooleanField(default=True)
    active                  = models.BooleanField(default=True)
    timestamp               = models.DateTimeField(auto_now_add=True)

    objects = CardManager()

    def __str__(self):
        return "{} {}".format(self.brand, self.last4)


def new_card_post_save_receiver(sender, instance, created, *args, **kwargs):
    if instance.default:
        billing_profile = instance.billing_profile
        qs = Card.objects.filter(billing_profile=billing_profile).exclude(pk=instance.pk)
        qs.update(default=False)


post_save.connect(new_card_post_save_receiver, sender=Card)



# stripe.Charge.create(
#   amount = int(order_obj.total * 100),
#   currency = "usd",
#   customer =  BillingProfile.objects.filter(email='hello@teamcfe.com').first().stripe_id,
#   source = Card.objects.filter(billing_profile__email='hello@teamcfe.com').first().stripe_id, # obtained with Stripe.js
#   description="Charge for elijah.martin@example.com"
# )

class ChargeManager(models.Manager):
    def do(self, billing_profile, order_obj, card=None): # Charge.objects.do()
        card_obj = card
        if card_obj is None:
            cards = billing_profile.card_set.filter(default=True) # card_obj.billing_profile
            if cards.exists():
                card_obj = cards.first()
        if card_obj is None:
            return False, "No cards available"
        c = stripe.Charge.create(
              amount = int(order_obj.total * 100), # 39.19 --> 3919
              currency = "usd",
              customer =  billing_profile.customer_id,
              source = card_obj.stripe_id,
              metadata={"order_id":order_obj.order_id},
            )
        new_charge_obj = self.model(
                billing_profile = billing_profile,
                stripe_id = c.id,
                paid = c.paid,
                refunded = c.refunded,
                outcome = c.outcome,
                outcome_type = c.outcome['type'],
                seller_message = c.outcome.get('seller_message'),
                risk_level = c.outcome.get('risk_level'),
        )
        new_charge_obj.save()
        return new_charge_obj.paid, new_charge_obj.seller_message


class Charge(models.Model):
    billing_profile         = models.ForeignKey(BillingProfile)
    stripe_id               = models.CharField(max_length=120)
    paid                    = models.BooleanField(default=False)
    refunded                = models.BooleanField(default=False)
    outcome                 = models.TextField(null=True, blank=True)
    outcome_type            = models.CharField(max_length=120, null=True, blank=True)
    seller_message          = models.CharField(max_length=120, null=True, blank=True)
    risk_level              = models.CharField(max_length=120, null=True, blank=True)

    objects = ChargeManager()





================================================
FILE: src/billing/templates/billing/payment-method.html
================================================
{% extends 'base.html' %}


{% block content %}

<div class='col-10 col-md-6 mx-auto'>
    <h1>Add Payment Method</h1>
    <div class='stripe-payment-form' data-token='{{ publish_key }}' data-next-url='{% if next_url %}{{ next_url }}{% endif %}' data-btn-title='Add New Card'></div>
</div>


{% endblock %}


================================================
FILE: src/billing/tests.py
================================================
from django.test import TestCase

# Create your tests here.


================================================
FILE: src/billing/views.py
================================================
from django.conf import settings
from django.http import JsonResponse, HttpResponse
from django.shortcuts import render, redirect
from django.utils.http import is_safe_url




import stripe
STRIPE_SECRET_KEY = getattr(settings, "STRIPE_SECRET_KEY", "sk_test_cu1lQmcg1OLffhLvYrSCp5XE")
STRIPE_PUB_KEY =  getattr(settings, "STRIPE_PUB_KEY", 'pk_test_PrV61avxnHaWIYZEeiYTTVMZ')
stripe.api_key = STRIPE_SECRET_KEY



from .models import BillingProfile, Card

def payment_method_view(request):
    #next_url = 
    # if request.user.is_authenticated():
    #     billing_profile = request.user.billingprofile
    #     my_customer_id = billing_profile.customer_id

    billing_profile, billing_profile_created = BillingProfile.objects.new_or_get(request)
    if not billing_profile:
        return redirect("/cart")
    next_url = None
    next_ = request.GET.get('next')
    if is_safe_url(next_, request.get_host()):
        next_url = next_
    return render(request, 'billing/payment-method.html', {"publish_key": STRIPE_PUB_KEY, "next_url": next_url})




def payment_method_createview(request):
    if request.method == "POST" and request.is_ajax():
        billing_profile, billing_profile_created = BillingProfile.objects.new_or_get(request)
        if not billing_profile:
            return HttpResponse({"message": "Cannot find this user"}, status_code=401)
        token = request.POST.get("token")
        if token is not None:
            new_card_obj = Card.objects.add_new(billing_profile, token)
        return JsonResponse({"message": "Success! Your card was added."})
    return HttpResponse("error", status_code=401)






================================================
FILE: src/carts/__init__.py
================================================


================================================
FILE: src/carts/admin.py
================================================
from django.contrib import admin


from .models import Cart

admin.site.register(Cart)

================================================
FILE: src/carts/apps.py
================================================
from django.apps import AppConfig


class CartsConfig(AppConfig):
    name = 'carts'


================================================
FILE: src/carts/migrations/0001_initial.py
================================================
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-09-26 00:27
from __future__ import unicode_literals

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

    initial = True

    dependencies = [
        ('products', '0009_product_timestamp'),
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
    ]

    operations = [
        migrations.CreateModel(
            name='Cart',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('total', models.DecimalField(decimal_places=2, default=0.0, max_digits=100)),
                ('updated', models.DateTimeField(auto_now=True)),
                ('timestamp', models.DateTimeField(auto_now_add=True)),
                ('products', models.ManyToManyField(blank=True, to='products.Product')),
                ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
            ],
        ),
    ]


================================================
FILE: src/carts/migrations/0002_cart_subtotal.py
================================================
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-09-26 01:23
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ('carts', '0001_initial'),
    ]

    operations = [
        migrations.AddField(
            model_name='cart',
            name='subtotal',
            field=models.DecimalField(decimal_places=2, default=0.0, max_digits=100),
        ),
    ]


================================================
FILE: src/carts/migrations/__init__.py
================================================


================================================
FILE: src/carts/models.py
================================================
from decimal import Decimal
from django.conf import settings
from django.db import models
from django.db.models.signals import pre_save, post_save, m2m_changed

from products.models import Product


User = settings.AUTH_USER_MODEL

class CartManager(models.Manager):
    def new_or_get(self, request):
        cart_id = request.session.get("cart_id", None)
        qs = self.get_queryset().filter(id=cart_id)
        if qs.count() == 1:
            new_obj = False
            cart_obj = qs.first()
            if request.user.is_authenticated() and cart_obj.user is None:
                cart_obj.user = request.user
                cart_obj.save()
        else:
            cart_obj = Cart.objects.new(user=request.user)
            new_obj = True
            request.session['cart_id'] = cart_obj.id
        return cart_obj, new_obj

    def new(self, user=None):
        user_obj = None
        if user is not None:
            if user.is_authenticated():
                user_obj = user
        return self.model.objects.create(user=user_obj)

class Cart(models.Model):
    user        = models.ForeignKey(User, null=True, blank=True)
    products    = models.ManyToManyField(Product, blank=True)
    subtotal    = models.DecimalField(default=0.00, max_digits=100, decimal_places=2)
    total       = models.DecimalField(default=0.00, max_digits=100, decimal_places=2)
    updated     = models.DateTimeField(auto_now=True)
    timestamp   = models.DateTimeField(auto_now_add=True)

    objects = CartManager()

    def __str__(self):
        return str(self.id)

    @property
    def is_digital(self):
        qs = self.products.all() #every product
        new_qs = qs.filter(is_digital=False) # every product that is not digial
        if new_qs.exists():
            return False
        return True




def m2m_changed_cart_receiver(sender, instance, action, *args, **kwargs):
    if action == 'post_add' or action == 'post_remove' or action == 'post_clear':
        products = instance.products.all()
        total = 0
        for x in products:
            total += x.price
        if instance.subtotal != total:
            instance.subtotal = total
            instance.save()

m2m_changed.connect(m2m_changed_cart_receiver, sender=Cart.products.through)




def pre_save_cart_receiver(sender, instance, *args, **kwargs):
    if instance.subtotal > 0:
        instance.total = Decimal(instance.subtotal) * Decimal(1.08) # 8% tax
    else:
        instance.total = 0.00

pre_save.connect(pre_save_cart_receiver, sender=Cart)















================================================
FILE: src/carts/templates/carts/checkout-done.html
================================================
{% extends "base.html" %}


{% block content %}
<div class='col-6 mx-auto py-5 text-center'>
  <h1 class='display-1'>Thank you for your order!!!</h1>
</div>

{% endblock %}

================================================
FILE: src/carts/templates/carts/checkout.html
================================================
{% extends "base.html" %}


{% block content %}
{% if not billing_profile %}
    <div class='row text-center'>
    <div class='col-12 col-md-6'>
        <p class='lead'>Login</p>
        {% include 'accounts/snippets/form.html' with form=login_form next_url=request.build_absolute_uri %}
    </div>
    <div class='col-12 col-md-6'> 
        Continue as Guest

        {% url "guest_register" as guest_register_url %}
        {% include 'accounts/snippets/form.html' with form=guest_form next_url=request.build_absolute_uri action_url=guest_register_url %}
    </div>

    </div>

{% else %}
            
        {% if not object.shipping_address and shipping_address_required %}

         <div class='row'>
            <div class='col-12'>
                <p class='lead'>Shipping Address</p>
                <hr/>
            </div>
            <div class='col-6'>
                

           

                    {% url "checkout_address_create" as checkout_address_create %}
                    {% include 'addresses/form.html' with form=address_form next_url=request.build_absolute_uri action_url=checkout_address_create address_type='shipping' %}'



             </div>
         <div class='col-6'>
            {% url 'checkout_address_reuse' as checkout_address_reuse %}
            {% include 'addresses/prev_addresses.html' with address_qs=address_qs next_url=request.build_absolute_uri address_type='shipping' action_url=checkout_address_reuse %}
            </div>
        </div>


        {% elif not object.billing_address %}
        <div class='row'>
            <div class='col-12'>
                 <p class='lead'>Billing Address</p>
                <hr/>
            </div>
            <div class='col-6'>
               
            {% url "checkout_address_create" as checkout_address_create %}
            {% include 'addresses/form.html' with form=address_form next_url=request.build_absolute_uri action_url=checkout_address_create address_type='billing' %}
            </div>
              <div class='col-6'>
                {% url 'checkout_address_reuse' as checkout_address_reuse %}
             {% include 'addresses/prev_addresses.html' with address_qs=address_qs next_url=request.build_absolute_uri  address_type='billing' action_url=checkout_address_reuse %}
         </div>

         
        </div>
        {% else %}
            {% if not has_card %}
                <!-- enter credit card here -->
                <div class='stripe-payment-form' data-token='{{ publish_key }}' data-next-url='{{ request.build_absolute_uri }}' data-btn-title='Add Payment Method'></div>

            {% else %}
                <h1>Finalize Checkout</h1>
                <p>Cart Items: {% for product in object.cart.products.all %}{{ product }}{% if not forloop.last %}, {% endif %}{% endfor %}</p>
                <p>Shipping Address: {{ object.shipping_address_final }}</p>
                <p>Billing Address: {{ object.billing_address_final }}</p>
                <p>Payment Method: {{ billing_profile.default_card }} (<a href="{{ billing_profile.get_payment_method_url }}?next={{ request.build_absolute_uri }}">Change</a>)</p>
                <p>Cart Total: {{ object.cart.total }}</p>
                <p>Shipping Total: {{ object.shipping_total }}</p>
                <p>Order Total: {{ object.total }}</p>

                <form class='form' method='POST' action="">{% csrf_token %}
                    <button type='submit' class='btn btn-success'>Checkout</button>
                </form>
            {% endif %}
        {% endif %}
{% endif %}



{% endblock %}

================================================
FILE: src/carts/templates/carts/home.html
================================================
{% extends "base.html" %}


{% block content %}
<h1>Cart</h1>

{% if cart.products.exists %}
<table class="table cart-table">
  <thead>
    <tr>
      <th>#</th>
      <th>Product Name</th>
      <th>Product Price</th>
    </tr>
  </thead>
  <tbody class='cart-body'>
    {% for product in cart.products.all %}
    <tr class='cart-product'>
      <th scope="row">{{ forloop.counter }}</th>
      <td><a href='{{ product.get_absolute_url }}'>{{ product.title }}</a> 
        {% include 'carts/snippets/remove-product.html' with product_id=product.id %}
      </td>
      <td>{{ product.price }}</td>
    </tr>
    {% endfor %}
    <tr>
      <td colspan="2"></td>
      <td><b>Subtotal</b> $<span class='cart-subtotal'>{{ cart.subtotal }}</span></td>
    </tr>
    <tr>
      <td colspan="2"></td>
      <td><b>Total</b> $<span class='cart-total'>{{ cart.total }}</span></td>
    </tr>
    <tr>
      <td colspan="2"></td>
      <td><a class='btn btn-lg btn-success' href='{% url "cart:checkout" %}'>Checkout</a></td>
    </tr>

  </tbody>
</table>

<div class='cart-item-remove-form' style='display:none'>

    {% include 'carts/snippets/remove-product.html' %}
  </div>

{% else %}
<p class='lead'>Cart is empty</p>
{% endif %}


{% endblock %}

================================================
FILE: src/carts/templates/carts/snippets/remove-product.html
================================================
<form class='form-product-ajax' method='POST' action='{% url "cart:update" %}' data-endpoint='{% url "cart:update" %}' class="form"> {% csrf_token %}
    <input class='cart-item-product-id' type='hidden' name='product_id' value='{{ product_id }}' />
      <button type='submit' class='btn btn-link btn-sm' style="padding:0px;cursor: pointer;">Remove?</button>
    </span>
</form>

================================================
FILE: src/carts/tests.py
================================================
from django.test import TestCase

# Create your tests here.


================================================
FILE: src/carts/urls.py
================================================
from django.conf.urls import url

from .views import (
        cart_home, 
        cart_update, 
        checkout_home,
        checkout_done_view
        )

urlpatterns = [
    url(r'^$', cart_home, name='home'),
    url(r'^checkout/success/$', checkout_done_view, name='success'),
    url(r'^checkout/$', checkout_home, name='checkout'),
    url(r'^update/$', cart_update, name='update'),
]

================================================
FILE: src/carts/views.py
================================================
from django.conf import settings
from django.http import JsonResponse
from django.shortcuts import render, redirect


from accounts.forms import LoginForm, GuestForm
from accounts.models import GuestEmail

from addresses.forms import AddressCheckoutForm
from addresses.models import Address

from billing.models import BillingProfile
from orders.models import Order
from products.models import Product
from .models import Cart


import stripe
STRIPE_SECRET_KEY = getattr(settings, "STRIPE_SECRET_KEY", "sk_test_cu1lQmcg1OLffhLvYrSCp5XE")
STRIPE_PUB_KEY =  getattr(settings, "STRIPE_PUB_KEY", 'pk_test_PrV61avxnHaWIYZEeiYTTVMZ')
stripe.api_key = STRIPE_SECRET_KEY



def cart_detail_api_view(request):
    cart_obj, new_obj = Cart.objects.new_or_get(request)
    products = [{
            "id": x.id,
            "url": x.get_absolute_url(),
            "name": x.name, 
            "price": x.price
            } 
            for x in cart_obj.products.all()]
    cart_data  = {"products": products, "subtotal": cart_obj.subtotal, "total": cart_obj.total}
    return JsonResponse(cart_data)

def cart_home(request):
    cart_obj, new_obj = Cart.objects.new_or_get(request)
    return render(request, "carts/home.html", {"cart": cart_obj})


def cart_update(request):
    product_id = request.POST.get('product_id')
    
    if product_id is not None:
        try:
            product_obj = Product.objects.get(id=product_id)
        except Product.DoesNotExist:
            print("Show message to user, product is gone?")
            return redirect("cart:home")
        cart_obj, new_obj = Cart.objects.new_or_get(request)
        if product_obj in cart_obj.products.all():
            cart_obj.products.remove(product_obj)
            added = False
        else:
            cart_obj.products.add(product_obj) # cart_obj.products.add(product_id)
            added = True
        request.session['cart_items'] = cart_obj.products.count()
        # return redirect(product_obj.get_absolute_url())
        if request.is_ajax(): # Asynchronous JavaScript And XML / JSON
            print("Ajax request")
            json_data = {
                "added": added,
                "removed": not added,
                "cartItemCount": cart_obj.products.count()
            }
            return JsonResponse(json_data, status=200) # HttpResponse
            # return JsonResponse({"message": "Error 400"}, status=400) # Django Rest Framework
    return redirect("cart:home")



def checkout_home(request):
    cart_obj, cart_created = Cart.objects.new_or_get(request)
    order_obj = None
    if cart_created or cart_obj.products.count() == 0:
        return redirect("cart:home")  
    
    login_form = LoginForm(request=request)
    guest_form = GuestForm(request=request)
    address_form = AddressCheckoutForm()
    billing_address_id = request.session.get("billing_address_id", None)

    shipping_address_required = not cart_obj.is_digital


    shipping_address_id = request.session.get("shipping_address_id", None)

    billing_profile, billing_profile_created = BillingProfile.objects.new_or_get(request)
    address_qs = None
    has_card = False
    if billing_profile is not None:
        if request.user.is_authenticated():
            address_qs = Address.objects.filter(billing_profile=billing_profile)
        order_obj, order_obj_created = Order.objects.new_or_get(billing_profile, cart_obj)
        if shipping_address_id:
            order_obj.shipping_address = Address.objects.get(id=shipping_address_id)
            del request.session["shipping_address_id"]
        if billing_address_id:
            order_obj.billing_address = Address.objects.get(id=billing_address_id) 
            del request.session["billing_address_id"]
        if billing_address_id or shipping_address_id:
            order_obj.save()
        has_card = billing_profile.has_card

    if request.method == "POST":
        "check that order is done"
        is_prepared = order_obj.check_done()
        if is_prepared:
            did_charge, crg_msg = billing_profile.charge(order_obj)
            if did_charge:
                order_obj.mark_paid() # sort a signal for us
                request.session['cart_items'] = 0
                del request.session['cart_id']
                if not billing_profile.user:
                    '''
                    is this the best spot?
                    '''
                    billing_profile.set_cards_inactive()
                return redirect("cart:success")
            else:
                print(crg_msg)
                return redirect("cart:checkout")
    context = {
        "object": order_obj,
        "billing_profile": billing_profile,
        "login_form": login_form,
        "guest_form": guest_form,
        "address_form": address_form,
        "address_qs": address_qs,
        "has_card": has_card,
        "publish_key": STRIPE_PUB_KEY,
        "shipping_address_required": shipping_address_required,
    }
    return render(request, "carts/checkout.html", context)







def checkout_done_view(request):
    return render(request, "carts/checkout-done.html", {})








================================================
FILE: src/ecommerce/__init__.py
================================================


================================================
FILE: src/ecommerce/aws/__init__.py
================================================


================================================
FILE: src/ecommerce/aws/conf.py
================================================
import datetime
import os

try:
    from .ignore2 import AWS_ACCESS_KEY_ID,  AWS_SECRET_ACCESS_KEY
except:
    AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID", "AKIAJARK375PALZJC55Q")
    AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY", "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")

AWS_GROUP_NAME = "CFE_eCommerce_Group"
AWS_USERNAME = "cfe-ecommerce-user"

AWS_FILE_EXPIRE = 200
AWS_PRELOAD_METADATA = True
AWS_QUERYSTRING_AUTH = False

DEFAULT_FILE_STORAGE = 'ecommerce.aws.utils.MediaRootS3BotoStorage'
STATICFILES_STORAGE = 'ecommerce.aws.utils.StaticRootS3BotoStorage'
AWS_STORAGE_BUCKET_NAME = 'cfe-ecommerce'
S3DIRECT_REGION = 'us-west-2'
S3_URL = '//%s.s3.amazonaws.com/' % AWS_STORAGE_BUCKET_NAME
MEDIA_URL = '//%s.s3.amazonaws.com/media/' % AWS_STORAGE_BUCKET_NAME
MEDIA_ROOT = MEDIA_URL
STATIC_URL = S3_URL + 'static/'
ADMIN_MEDIA_PREFIX = STATIC_URL + 'admin/'

two_months = datetime.timedelta(days=61)
date_two_months_later = datetime.date.today() + two_months
expires = date_two_months_later.strftime("%A, %d %B %Y 20:00:00 GMT")

AWS_HEADERS = { 
 'Expires': expires,
 'Cache-Control': 'max-age=%d' % (int(two_months.total_seconds()), ),
}

PROTECTED_DIR_NAME = 'protected'
PROTECTED_MEDIA_URL = '//%s.s3.amazonaws.com/%s/' %( AWS_STORAGE_BUCKET_NAME, PROTECTED_DIR_NAME)

AWS_DOWNLOAD_EXPIRE = 5000 #(0ptional, in milliseconds)





================================================
FILE: src/ecommerce/aws/download/__init__.py
================================================


================================================
FILE: src/ecommerce/aws/download/utils.py
================================================
import boto
import re
import os

from django.conf import settings
from boto.s3.connection import OrdinaryCallingFormat


class AWSDownload(object):
    access_key = None
    secret_key = None
    bucket = None
    region = None
    expires = getattr(settings, 'AWS_DOWNLOAD_EXPIRE', 5000)

    def __init__(self,  access_key, secret_key, bucket, region, *args, **kwargs):
        self.bucket = bucket
        self.access_key = access_key
        self.secret_key = secret_key
        self.region = region
        super(AWSDownload, self).__init__(*args, **kwargs)

    def s3connect(self):
        conn = boto.s3.connect_to_region(
                self.region,
                aws_access_key_id=self.access_key, 
                aws_secret_access_key=self.secret_key,
                is_secure=True,
                calling_format=OrdinaryCallingFormat()
            )
        return conn

    def get_bucket(self):
        conn = self.s3connect()
        bucket_name = self.bucket
        bucket = conn.get_bucket(bucket_name)
        return bucket

    def get_key(self, path):
        bucket = self.get_bucket()
        key = bucket.get_key(path)
        return key

    def get_filename(self, path, new_filename=None):
        current_filename =  os.path.basename(path)
        if new_filename is not None:
            filename, file_extension = os.path.splitext(current_filename)
            escaped_new_filename_base = re.sub(
                                            '[^A-Za-z0-9\#]+', 
                                            '-', 
                                            new_filename)
            escaped_filename = escaped_new_filename_base + file_extension
            return escaped_filename
        return current_filename

    def generate_url(self, path, download=True, new_filename=None):
        file_url = None
        aws_obj_key = self.get_key(path)
        if aws_obj_key:
            headers = None
            if download:
                filename = self.get_filename(path, new_filename=new_filename)
                headers = {
                    'response-content-type': 'application/force-download',
                    'response-content-disposition':'attachment;filename="%s"'%filename
                }
            file_url = aws_obj_key.generate_url(
                                response_headers=headers,
                                 expires_in=self.expires, 
                                method='GET') 
        return file_url

================================================
FILE: src/ecommerce/aws/utils.py
================================================
from storages.backends.s3boto3 import S3Boto3Storage

StaticRootS3BotoStorage = lambda: S3Boto3Storage(location='static')
MediaRootS3BotoStorage  = lambda: S3Boto3Storage(location='media')
ProtectedS3Storage  = lambda: S3Boto3Storage(location='protected')

================================================
FILE: src/ecommerce/forms.py
================================================
from django import forms
from django.contrib.auth import get_user_model

User = get_user_model()

class ContactForm(forms.Form):
    fullname = forms.CharField(
            widget=forms.TextInput(
                    attrs={
                        "class": "form-control", 
                        "placeholder": "Your full name"
                    }
                    )
            )
    email    = forms.EmailField(
            widget=forms.EmailInput(
                    attrs={
                        "class": "form-control", 
                        "placeholder": "Your email"
                    }
                    )
            )
    content  = forms.CharField(
            widget=forms.Textarea(
                attrs={
                    'class': 'form-control',
                    "placeholder": "Your message" 
                    }
                )
            )

    # def clean_email(self):
    #     email = self.cleaned_data.get("email")
    #     if not "gmail.com" in email:
    #         raise forms.ValidationError("Email has to be gmail.com")
    #     return email

    # def clean_content(self):
    #     raise forms.ValidationError("Content is wrong.")

















================================================
FILE: src/ecommerce/mixins.py
================================================
from django.utils.http import is_safe_url


class RequestFormAttachMixin(object):
    def get_form_kwargs(self):
        kwargs = super(RequestFormAttachMixin, self).get_form_kwargs()
        kwargs['request'] = self.request
        return kwargs


class NextUrlMixin(object):
    default_next = "/"
    def get_next_url(self):
        request = self.request
        next_ = request.GET.get('next')
        next_post = request.POST.get('next')
        redirect_path = next_ or next_post or None
        if is_safe_url(redirect_path, request.get_host()):
                return redirect_path
        return self.default_next

================================================
FILE: src/ecommerce/settings/__init__.py
================================================
from .base import *

from .production import *

try:
    from .local import *
except:
    pass

try:
    from .local_justin import *
except:
    pass

================================================
FILE: src/ecommerce/settings/base.py
================================================
"""
Django settings for ecommerce project.

Generated by 'django-admin startproject' using Django 1.11.4.

For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '@!-)jwmuzh8btr380g61=g+#&zzei&dz2(&=xbvxztady)_p(r'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []

EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = 'hungrypy@gmail.com' 
EMAIL_HOST_PASSWORD = 'yourpassword'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
DEFAULT_FROM_EMAIL = 'Python ecommerce <hungrypy@gmail.com>'
BASE_URL = '127.0.0.1:8000'


MANAGERS = (
    ('Justin Mitchel', "hungrypy@gmail.com"),
)

ADMINS = MANAGERS



# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # third party
    'storages',

    #our apps
    'accounts',
    'addresses',
    'analytics',
    'billing',
    'carts',
    'marketing',
    'orders',
    'products',
    'search',
    'tags',
]

AUTH_USER_MODEL = 'accounts.User' #changes the built-in user model to ours
LOGIN_URL = '/login/'
LOGIN_URL_REDIRECT = '/'
LOGOUT_URL = '/logout/'

FORCE_SESSION_TO_ONE = False
FORCE_INACTIVE_USER_ENDSESSION= False



MAILCHIMP_API_KEY = "717d0854ed20fed3be3689a3f125915c-us17"
MAILCHIMP_DATA_CENTER = "us17"
MAILCHIMP_EMAIL_LIST_ID = "e2ef12efee"


STRIPE_SECRET_KEY = "sk_test_cu1lQmcg1OLffhLvYrSCp5XE"
STRIPE_PUB_KEY = 'pk_test_PrV61avxnHaWIYZEeiYTTVMZ'


MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

LOGOUT_REDIRECT_URL = '/login/'
ROOT_URLCONF = 'ecommerce.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'ecommerce.wsgi.application'


# Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}


# Password validation
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/

STATIC_URL = '/static/'

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static_my_proj"),
]

STATIC_ROOT = os.path.join(os.path.dirname(BASE_DIR), "static_cdn", "static_root")


MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(os.path.dirname(BASE_DIR), "static_cdn", "media_root")


PROTECTED_ROOT = os.path.join(os.path.dirname(BASE_DIR), "static_cdn", "protected_media")



from ecommerce.aws.conf import *


CORS_REPLACE_HTTPS_REFERER      = False
HOST_SCHEME                     = "http://"
SECURE_PROXY_SSL_HEADER         = None
SECURE_SSL_REDIRECT             = False
SESSION_COOKIE_SECURE           = False
CSRF_COOKIE_SECURE              = False
SECURE_HSTS_SECONDS             = None
SECURE_HSTS_INCLUDE_SUBDOMAINS  = False
SECURE_FRAME_DENY               = False





================================================
FILE: src/ecommerce/settings/local.py
================================================
"""
Django settings for ecommerce project.

Generated by 'django-admin startproject' using Django 1.11.4.

For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '@!-)jwmuzh8btr380g61=g+#&zzei&dz2(&=xbvxztady)_p(r'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = ['0.0.0.0', '127.0.0.1']

EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = 'hungrypy@gmail.com' # sendgrid
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD', 'yourpassword')
EMAIL_PORT = 587
EMAIL_USE_TLS = True
DEFAULT_FROM_EMAIL = 'Python ecommerce <hungrypy@gmail.com>'
BASE_URL = '127.0.0.1:8000'

MANAGERS = (
    ('Justin Mitchel', "hungrypy@gmail.com"),
)

ADMINS = MANAGERS

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # third party
    'storages',

    #our apps
    'accounts',
    'addresses',
    'analytics',
    'billing',
    'carts',
    'marketing',
    'orders',
    'products',
    'search',
    'tags',
]

AUTH_USER_MODEL = 'accounts.User' #changes the built-in user model to ours
LOGIN_URL = '/login/'
LOGIN_URL_REDIRECT = '/'
LOGOUT_URL = '/logout/'

FORCE_SESSION_TO_ONE = False
FORCE_INACTIVE_USER_ENDSESSION= False



MAILCHIMP_API_KEY = os.environ.get("MAILCHIMP_API_KEY")
MAILCHIMP_DATA_CENTER = "us17"
MAILCHIMP_EMAIL_LIST_ID = os.environ.get("MAILCHIMP_EMAIL_LIST_ID")


STRIPE_SECRET_KEY = os.environ.get("STRIPE_SECRET_KEY", "sk_test_cu1lQmcg1OLffhLvYrSCp5XE")
STRIPE_PUB_KEY = os.environ.get("STRIPE_PUB_KEY", 'pk_test_PrV61avxnHaWIYZEeiYTTVMZ')


MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

LOGOUT_REDIRECT_URL = '/login/'
ROOT_URLCONF = 'ecommerce.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'ecommerce.wsgi.application'


# Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}


# Password validation
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'America/Los_Angeles' #'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/

STATIC_URL = '/static/'

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static_my_proj"),
]

STATIC_ROOT = os.path.join(os.path.dirname(BASE_DIR), "static_cdn", "static_root")


MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(os.path.dirname(BASE_DIR), "static_cdn", "media_root")


PROTECTED_ROOT = os.path.join(os.path.dirname(BASE_DIR), "static_cdn", "protected_media")

from ecommerce.aws.conf import *


CORS_REPLACE_HTTPS_REFERER      = False
HOST_SCHEME                     = "http://"
SECURE_PROXY_SSL_HEADER         = None
SECURE_SSL_REDIRECT             = False
SESSION_COOKIE_SECURE           = False
CSRF_COOKIE_SECURE              = False
SECURE_HSTS_SECONDS             = None
SECURE_HSTS_INCLUDE_SUBDOMAINS  = False
SECURE_FRAME_DENY               = False







================================================
FILE: src/ecommerce/settings/production.py
================================================
"""
Django settings for ecommerce project.

Generated by 'django-admin startproject' using Django 1.11.4.

For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ.get('SECRET_KEY')



EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = 'hungrypy@gmail.com' 
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD')
EMAIL_PORT = 587
EMAIL_USE_TLS = True
DEFAULT_FROM_EMAIL = 'Python ecommerce <hungrypy@gmail.com>'
BASE_URL = 'https://www.pythonecommerce.com/'

MANAGERS = (
    ('Justin Mitchel', "hungrypy@gmail.com"),
)

ADMINS = MANAGERS



# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False

ALLOWED_HOSTS = ['.pythonecommerce.com']


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # third party
    'storages',

    #our apps
    'accounts',
    'addresses',
    'analytics',
    'billing',
    'carts',
    'marketing',
    'orders',
    'products',
    'search',
    'tags',
]

AUTH_USER_MODEL = 'accounts.User' #changes the built-in user model to ours
LOGIN_URL = '/login/'
LOGIN_URL_REDIRECT = '/'
LOGOUT_URL = '/logout/'

FORCE_SESSION_TO_ONE = False
FORCE_INACTIVE_USER_ENDSESSION= False



MAILCHIMP_API_KEY = os.environ.get("MAILCHIMP_API_KEY")
MAILCHIMP_DATA_CENTER = "us17"
MAILCHIMP_EMAIL_LIST_ID = os.environ.get("MAILCHIMP_EMAIL_LIST_ID")


STRIPE_SECRET_KEY = os.environ.get("STRIPE_SECRET_KEY", "sk_test_cu1lQmcg1OLffhLvYrSCp5XE")
STRIPE_PUB_KEY = os.environ.get("STRIPE_PUB_KEY", 'pk_test_PrV61avxnHaWIYZEeiYTTVMZ')


MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

LOGOUT_REDIRECT_URL = '/login/'
ROOT_URLCONF = 'ecommerce.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'ecommerce.wsgi.application'


# Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

import dj_database_url
db_from_env = dj_database_url.config() #postgreSQL Database in heroku
DATABASES['default'].update(db_from_env)
DATABASES['default']['CONN_MAX_AGE'] = 500


# Password validation
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/

STATIC_URL = '/static/'

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static_my_proj"),
]

STATIC_ROOT = os.path.join(os.path.dirname(BASE_DIR), "static_cdn", "static_root")


MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(os.path.dirname(BASE_DIR), "static_cdn", "media_root")


PROTECTED_ROOT = os.path.join(os.path.dirname(BASE_DIR), "static_cdn", "protected_media")

from ecommerce.aws.conf import *


# https://kirr.co/vklau5

# Let's Encrypt ssl/tls https

CORS_REPLACE_HTTPS_REFERER      = True
HOST_SCHEME                     = "https://"
SECURE_PROXY_SSL_HEADER         = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_SSL_REDIRECT             = True
SESSION_COOKIE_SECURE           = True
CSRF_COOKIE_SECURE              = True
SECURE_HSTS_INCLUDE_SUBDOMAINS  = True
SECURE_HSTS_SECONDS             = 1000000
SECURE_FRAME_DENY               = True










================================================
FILE: src/ecommerce/urls.py
================================================
"""ecommerce URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.conf.urls import url, include
    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
"""

from django.conf import settings
from django.conf.urls.static import static

from django.conf.urls import url, include
from django.contrib import admin
from django.contrib.auth.views import LogoutView
from django.views.generic import TemplateView, RedirectView


from accounts.views import LoginView, RegisterView, GuestRegisterView
from addresses.views import (
    AddressCreateView,
    AddressListView,
    AddressUpdateView,
    checkout_address_create_view, 
    checkout_address_reuse_view
    )
from analytics.views import SalesView, SalesAjaxView
from billing.views import payment_method_view, payment_method_createview
from carts.views import cart_detail_api_view
from marketing.views import MarketingPreferenceUpdateView, MailchimpWebhookView
from orders.views import LibraryView

from .views import home_page, about_page, contact_page

urlpatterns = [
    url(r'^$', home_page, name='home'),
    url(r'^about/$', about_page, name='about'),
    #url(r'^accounts/login/$', RedirectView.as_view(url='/login')),
    url(r'^accounts/$', RedirectView.as_view(url='/account')),
    url(r'^account/', include("accounts.urls", namespace='account')),
    url(r'^accounts/', include("accounts.passwords.urls")),
    url(r'^address/$', RedirectView.as_view(url='/addresses')),
    url(r'^addresses/$', AddressListView.as_view(), name='addresses'),
    url(r'^addresses/create/$', AddressCreateView.as_view(), name='address-create'),
    url(r'^addresses/(?P<pk>\d+)/$', AddressUpdateView.as_view(), name='address-update'),
    url(r'^analytics/sales/$', SalesView.as_view(), name='sales-analytics'),
    url(r'^analytics/sales/data/$', SalesAjaxView.as_view(), name='sales-analytics-data'),
    url(r'^contact/$', contact_page, name='contact'),
    url(r'^login/$', LoginView.as_view(), name='login'),
    url(r'^checkout/address/create/$', checkout_address_create_view, name='checkout_address_create'),
    url(r'^checkout/address/reuse/$', checkout_address_reuse_view, name='checkout_address_reuse'),
    url(r'^register/guest/$', GuestRegisterView.as_view(), name='guest_register'),
    url(r'^logout/$', LogoutView.as_view(), name='logout'),
    url(r'^api/cart/$', cart_detail_api_view, name='api-cart'),
    url(r'^cart/', include("carts.urls", namespace='cart')),
    url(r'^billing/payment-method/$', payment_method_view, name='billing-payment-method'),
    url(r'^billing/payment-method/create/$', payment_method_createview, name='billing-payment-method-endpoint'),
    url(r'^register/$', RegisterView.as_view(), name='register'),
    url(r'^bootstrap/$', TemplateView.as_view(template_name='bootstrap/example.html')),
    url(r'^library/$', LibraryView.as_view(), name='library'),
    url(r'^orders/', include("orders.urls", namespace='orders')),
    url(r'^products/', include("products.urls", namespace='products')),
    url(r'^search/', include("search.urls", namespace='search')),
    url(r'^settings/$', RedirectView.as_view(url='/account')),
    url(r'^settings/email/$', MarketingPreferenceUpdateView.as_view(), name='marketing-pref'),
    url(r'^webhooks/mailchimp/$', MailchimpWebhookView.as_view(), name='webhooks-mailchimp'),
    url(r'^admin/', admin.site.urls),
]


if settings.DEBUG:
    urlpatterns = urlpatterns + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
    urlpatterns = urlpatterns + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)


================================================
FILE: src/ecommerce/utils.py
================================================

import datetime 
import os
import random
import string

from django.utils import timezone
from django.utils.text import slugify



def get_last_month_data(today):
    '''
    Simple method to get the datetime objects for the 
    start and end of last month. 
    '''
    this_month_start = datetime.datetime(today.year, today.month, 1)
    last_month_end = this_month_start - datetime.timedelta(days=1)
    last_month_start = datetime.datetime(last_month_end.year, last_month_end.month, 1)
    return (last_month_start, last_month_end)


def get_month_data_range(months_ago=1, include_this_month=False):
    '''
    A method that generates a list of dictionaires 
    that describe any given amout of monthly data.
    '''
    today = datetime.datetime.now().today()
    dates_ = []
    if include_this_month:
        # get next month's data with:
        next_month = today.replace(day=28) + datetime.timedelta(days=4)
        # use next month's data to get this month's data breakdown
        start, end = get_last_month_data(next_month)
        dates_.insert(0, {
            "start": start.timestamp(),
            "end": end.timestamp(),
            "start_json": start.isoformat(),
            "end": end.timestamp(),
            "end_json": end.isoformat(),
            "timesince": 0,
            "year": start.year,
            "month": str(start.strftime("%B")),
            })
    for x in range(0, months_ago):
        start, end = get_last_month_data(today)
        today = start
        dates_.insert(0, {
            "start": start.timestamp(),
            "start_json": start.isoformat(),
            "end": end.timestamp(),
            "end_json": end.isoformat(),
            "timesince": int((datetime.datetime.now() - end).total_seconds()),
            "year": start.year,
            "month": str(start.strftime("%B"))
        })
    #dates_.reverse()
    return dates_ 


def get_filename(path): #/abc/filename.mp4
    return os.path.basename(path)


def random_string_generator(size=10, chars=string.ascii_lowercase + string.digits):
    return ''.join(random.choice(chars) for _ in range(size))


def unique_key_generator(instance):
    """
    This is for a Django project with an key field
    """
    size = random.randint(30, 45)
    key = random_string_generator(size=size)

    Klass = instance.__class__
    qs_exists = Klass.objects.filter(key=key).exists()
    if qs_exists:
        return unique_slug_generator(instance)
    return key


def unique_order_id_generator(instance):
    """
    This is for a Django project with an order_id field
    """
    order_new_id = random_string_generator()

    Klass = instance.__class__
    qs_exists = Klass.objects.filter(order_id=order_new_id).exists()
    if qs_exists:
        return unique_slug_generator(instance)
    return order_new_id





def unique_slug_generator(instance, new_slug=None):
    """
    This is for a Django project and it assumes your instance 
    has a model with a slug field and a title character (char) field.
    """
    if new_slug is not None:
        slug = new_slug
    else:
        slug = slugify(instance.title)

    Klass = instance.__class__
    qs_exists = Klass.objects.filter(slug=slug).exists()
    if qs_exists:
        new_slug = "{slug}-{randstr}".format(
                    slug=slug,
                    randstr=random_string_generator(size=4)
                )
        return unique_slug_generator(instance, new_slug=new_slug)
    return slug

================================================
FILE: src/ecommerce/views.py
================================================
from django.contrib.auth import authenticate, login, get_user_model
from django.http import HttpResponse, JsonResponse
from django.shortcuts import render,redirect

from .forms import ContactForm

def home_page(request):
    # print(request.session.get("first_name", "Unknown"))
    # request.session['first_name']
    context = {
        "title":"Hello World!",
        "content":" Welcome to the homepage.",

    }
    if request.user.is_authenticated():
        context["premium_content"] = "YEAHHHHHH"
    return render(request, "home_page.html", context)

def about_page(request):
    context = {
        "title":"About Page",
        "content":" Welcome to the about page."
    }
    return render(request, "home_page.html", context)

def contact_page(request):
    contact_form = ContactForm(request.POST or None)
    context = {
        "title":"Contact",
        "content":" Welcome to the contact page.",
        "form": contact_form,
    }
    if contact_form.is_valid():
        print(contact_form.cleaned_data)
        if request.is_ajax():
            return JsonResponse({"message": "Thank you for your submission"})

    if contact_form.errors:
        errors = contact_form.errors.as_json()
        if request.is_ajax():
            return HttpResponse(errors, status=400, content_type='application/json')

    # if request.method == "POST":
    #     #print(request.POST)
    #     print(request.POST.get('fullname'))
    #     print(request.POST.get('email'))
    #     print(request.POST.get('content'))
    return render(request, "contact/view.html", context)





def home_page_old(request):
    html_ = """
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <!-- Required meta tags -->
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

        <!-- Bootstrap CSS -->
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
      </head>
      <body>
        <div class='text-center'>
            <h1>Hello, world!</h1>
        </div>
        <!-- Optional JavaScript -->
        <!-- jQuery first, then Popper.js, then Bootstrap JS -->
        <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>
      </body>
    </html>
    """
    return HttpResponse(html_)




================================================
FILE: src/ecommerce/wsgi.py
================================================
"""
WSGI config for ecommerce project.

It exposes the WSGI callable as a module-level variable named ``application``.

For more information on this file, see
https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/
"""

import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ecommerce.settings")

application = get_wsgi_application()


================================================
FILE: src/manage.py
================================================
#!/usr/bin/env python
import os
import sys

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ecommerce.settings")
    try:
        from django.core.management import execute_from_command_line
    except ImportError:
        # The above import may fail for some other reason. Ensure that the
        # issue is really that Django is missing to avoid masking other
        # exceptions on Python 2.
        try:
            import django
        except ImportError:
            raise ImportError(
                "Couldn't import Django. Are you sure it's installed and "
                "available on your PYTHONPATH environment variable? Did you "
                "forget to activate a virtual environment?"
            )
        raise
    execute_from_command_line(sys.argv)


================================================
FILE: src/marketing/__init__.py
================================================


================================================
FILE: src/marketing/admin.py
================================================
from django.contrib import admin

from .models import MarketingPreference

class MarketingPreferenceAdmin(admin.ModelAdmin):
    list_display  = ['__str__', 'subscribed', 'updated']
    readonly_fields = ['mailchimp_msg', 'mailchimp_subscribed', 'timestamp', 'updated']
    class Meta:
        model = MarketingPreference
        fields = [
                    'user', 
                    'subscribed', 
                    'mailchimp_msg',
                    'mailchimp_subscribed', 
                    'timestamp', 
                    'updated'
                ]

admin.site.register(MarketingPreference, MarketingPreferenceAdmin)

================================================
FILE: src/marketing/apps.py
================================================
from django.apps import AppConfig


class MarketingConfig(AppConfig):
    name = 'marketing'


================================================
FILE: src/marketing/forms.py
================================================
from django import forms

from .models import MarketingPreference


class MarketingPreferenceForm(forms.ModelForm):
    subscribed = forms.BooleanField(label='Receive Marketing Email?', required=False)
    class Meta:
        model = MarketingPreference
        fields = [
            'subscribed'
        ]

================================================
FILE: src/marketing/migrations/0001_initial.py
================================================
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-10-18 00:36
from __future__ import unicode_literals

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='MarketingPreference',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('subscribed', models.BooleanField(default=True)),
                ('mailchimp_msg', models.TextField(blank=True, null=True)),
                ('timestamp', models.DateTimeField(auto_now_add=True)),
                ('update', models.DateTimeField(auto_now=True)),
                ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
            ],
        ),
    ]


================================================
FILE: src/marketing/migrations/0002_marketingpreference_mailchimp_subscribed.py
================================================
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-10-18 01:34
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ('marketing', '0001_initial'),
    ]

    operations = [
        migrations.AddField(
            model_name='marketingpreference',
            name='mailchimp_subscribed',
            field=models.NullBooleanField(),
        ),
    ]


================================================
FILE: src/marketing/migrations/0003_auto_20171018_0142.py
================================================
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-10-18 01:42
from __future__ import unicode_literals

from django.db import migrations


class Migration(migrations.Migration):

    dependencies = [
        ('marketing', '0002_marketingpreference_mailchimp_subscribed'),
    ]

    operations = [
        migrations.RenameField(
            model_name='marketingpreference',
            old_name='update',
            new_name='updated',
        ),
    ]


================================================
FILE: src/marketing/migrations/__init__.py
================================================


================================================
FILE: src/marketing/mixins.py
================================================
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt


class CsrfExemptMixin(object):
    @method_decorator(csrf_exempt)
    def dispatch(self, request, *args, **kwargs):
        return super(CsrfExemptMixin, self).dispatch(request, *args, **kwargs)



================================================
FILE: src/marketing/models.py
================================================
from django.conf import settings
from django.db import models
from django.db.models.signals import post_save, pre_save

from .utils import Mailchimp

class MarketingPreference(models.Model):
    user                        = models.OneToOneField(settings.AUTH_USER_MODEL)
    subscribed                  = models.BooleanField(default=True)
    mailchimp_subscribed        = models.NullBooleanField(blank=True)
    mailchimp_msg               = models.TextField(null=True, blank=True)
    timestamp                   = models.DateTimeField(auto_now_add=True)
    updated                      = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.user.email




def marketing_pref_create_receiver(sender, instance, created, *args, **kwargs):
    if created:
        status_code, response_data = Mailchimp().subscribe(instance.user.email)
        print(status_code, response_data)


post_save.connect(marketing_pref_create_receiver, sender=MarketingPreference)

def marketing_pref_update_receiver(sender, instance, *args, **kwargs):
    if instance.subscribed != instance.mailchimp_subscribed:
        if instance.subscribed:
            # subscribing user
            status_code, response_data = Mailchimp().subscribe(instance.user.email)
        else:
            # unsubscribing user
            status_code, response_data = Mailchimp().unsubscribe(instance.user.email)

        if response_data['status'] == 'subscribed':
            instance.subscribed = True
            instance.mailchimp_subscribed = True
            instance.mailchimp_msg = response_data
        else:
            instance.subscribed = False
            instance.mailchimp_subscribed = False
            instance.mailchimp_msg = response_data

pre_save.connect(marketing_pref_update_receiver, sender=MarketingPreference)



def make_marketing_pref_receiver(sender, instance, created, *args, **kwargs):
    '''
    User model
    '''
    if created:
        MarketingPreference.objects.get_or_create(user=instance)

post_save.connect(make_marketing_pref_receiver, sender=settings.AUTH_USER_MODEL)





================================================
FILE: src/marketing/tests.py
================================================
from django.test import TestCase

# Create your tests here.


================================================
FILE: src/marketing/utils.py
================================================
import hashlib
import json
import re
import requests
from django.conf import settings


MAILCHIMP_API_KEY = getattr(settings, "MAILCHIMP_API_KEY", None)
MAILCHIMP_DATA_CENTER = getattr(settings, "MAILCHIMP_DATA_CENTER", None)
MAILCHIMP_EMAIL_LIST_ID = getattr(settings, "MAILCHIMP_EMAIL_LIST_ID", None)



def check_email(email):
    if not re.match(r".+@.+\..+", email):
        raise ValueError('String passed is not a valid email address')
    return email

def get_subscriber_hash(member_email):
    check_email(member_email)
    member_email = member_email.lower().encode()
    m = hashlib.md5(member_email)
    return m.hexdigest()



class Mailchimp(object):
    def __init__(self):
        super(Mailchimp, self).__init__()
        self.key = MAILCHIMP_API_KEY
        self.api_url = "https://{dc}.api.mailchimp.com/3.0".format(
                    dc=MAILCHIMP_DATA_CENTER
                    )
        self.list_id = MAILCHIMP_EMAIL_LIST_ID
        self.list_endpoint = '{api_url}/lists/{list_id}'.format(
                                    api_url = self.api_url,
                                    list_id=self.list_id
                        )

    
    def get_members_endpoint(self):
        return self.list_endpoint + "/members"

    def change_subcription_status(self, email, status='unsubscribed'):
        hashed_email = get_subscriber_hash(email)
        endpoint = self.get_members_endpoint() + "/" +  hashed_email
        data = {
            "status": self.check_valid_status(status)
        }
        r = requests.put(endpoint, auth=("", self.key), data=json.dumps(data))
        return r.status_code, r.json()


    def check_subcription_status(self, email):
        hashed_email = get_subscriber_hash(email)
        endpoint = self.get_members_endpoint() + "/" +  hashed_email
        r = requests.get(endpoint, auth=("", self.key))
        return r.status_code, r.json()

    def check_valid_status(self, status):
        choices = ['subscribed', 'unsubscribed', 'cleaned', 'pending']
        if status not in choices:
            raise ValueError("Not a valid choice for email status")
        return status

    def add_email(self, email):
        # status = "subscribed"
        # self.check_valid_status(status)
        # data = {
        #     "email_address": email,
        #     "status": status
        # }
        # endpoint = self.get_members_endpoint()
        # r = requests.post(endpoint, auth=("", self.key), data=json.dumps(data))
        return self.change_subcription_status(email, status='subscribed')

    def unsubscribe(self, email):
        return self.change_subcription_status(email, status='unsubscribed')

    def subscribe(self, email):
        return self.change_subcription_status(email, status='subscribed')

    def pending(self, email):
        return self.change_subcription_status(email, status='pending')



================================================
FILE: src/marketing/views.py
================================================
from django.conf import settings

from django.contrib.messages.views import SuccessMessageMixin
from django.http import HttpResponse
from django.views.generic import UpdateView, View
from django.shortcuts import render, redirect


from .forms import MarketingPreferenceForm
from .mixins import CsrfExemptMixin
from .models import MarketingPreference
from .utils import Mailchimp
MAILCHIMP_EMAIL_LIST_ID = getattr(settings, "MAILCHIMP_EMAIL_LIST_ID", None)

class MarketingPreferenceUpdateView(SuccessMessageMixin, UpdateView):
    form_class = MarketingPreferenceForm
    template_name = 'base/forms.html' # yeah create this
    success_url = '/settings/email/'
    success_message = 'Your email preferences have been updated. Thank you.'

    def dispatch(self, *args, **kwargs):
        user = self.request.user
        if not user.is_authenticated():
            return redirect("/login/?next=/settings/email/") # HttpResponse("Not allowed", status=400)
        return super(MarketingPreferenceUpdateView, self).dispatch(*args, **kwargs)

    def get_context_data(self, *args, **kwargs):
        context = super(MarketingPreferenceUpdateView, self).get_context_data(*args, **kwargs)
        context['title'] = 'Update Email Preferences'
        return context

    def get_object(self):
        user = self.request.user
        obj, created = MarketingPreference.objects.get_or_create(user=user) # get_absolute_url
        return obj






"""
POST METHOD
data[list_id]: e2ef12efee
fired_at: 2017-10-18 18:49:49
data[merges][FNAME]:
data[email]: hello@teamcfe.com
data[merges][LNAME]:
data[email_type]: html
data[reason]: manual
data[merges][BIRTHDAY]:
data[id]: d686033a32
data[merges][EMAIL]: hello@teamcfe.com
data[ip_opt]: 108.184.68.3
data[web_id]: 349661
type: unsubscribe
data[action]: unsub
"""

class MailchimpWebhookView(CsrfExemptMixin, View): # HTTP GET -- def get() CSRF?????
    # def get(self, request, *args, **kwargs):
    #     return HttpResponse("Thank you", status=200)
    def post(self, request, *args, **kwargs):
        data = request.POST
        list_id = data.get('data[list_id]')
        if str(list_id) == str(MAILCHIMP_EMAIL_LIST_ID):
            hook_type = data.get("type")
            email = data.get('data[email]')
            response_status, response = Mailchimp().check_subcription_status(email)
            sub_status  = response['status']
            is_subbed = None
            mailchimp_subbed = None
            if sub_status == "subscribed":
                is_subbed, mailchimp_subbed  = (True, True)
            elif sub_status == "unsubscribed":
                is_subbed, mailchimp_subbed  = (False, False)
            if is_subbed is not None and mailchimp_subbed is not None:
                qs = MarketingPreference.objects.filter(user__email__iexact=email)
                if qs.exists():
                    qs.update(
                            subscribed=is_subbed, 
                            mailchimp_subscribed=mailchimp_subbed, 
                            mailchimp_msg=str(data))
        return HttpResponse("Thank you", status=200)

# def mailchimp_webhook_view(request):
#     data = request.POST
#     list_id = data.get('data[list_id]')
#     if str(list_id) == str(MAILCHIMP_EMAIL_LIST_ID):
#         hook_type = data.get("type")
#         email = data.get('data[email]')
#         response_status, response = Mailchimp().check_subcription_status(email)
#         sub_status  = response['status']
#         is_subbed = None
#         mailchimp_subbed = None
#         if sub_status == "subscribed":
#             is_subbed, mailchimp_subbed  = (True, True)
#         elif sub_status == "unsubscribed":
#             is_subbed, mailchimp_subbed  = (False, False)
#         if is_subbed is not None and mailchimp_subbed is not None:
#             qs = MarketingPreference.objects.filter(user__email__iexact=email)
#             if qs.exists():
#                 qs.update(
#                         subscribed=is_subbed, 
#                         mailchimp_subscribed=mailchimp_subbed, 
#                         mailchimp_msg=str(data))
#     return HttpResponse("Thank you", status=200)





================================================
FILE: src/orders/__init__.py
================================================


================================================
FILE: src/orders/admin.py
================================================
from django.contrib import admin

from .models import Order, ProductPurchase

admin.site.register(Order)

admin.site.register(ProductPurchase)

================================================
FILE: src/orders/apps.py
================================================
from django.apps import AppConfig


class OrdersConfig(AppConfig):
    name = 'orders'


================================================
FILE: src/orders/migrations/0001_initial.py
================================================
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-09-27 23:00
from __future__ import unicode_literals

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

    initial = True

    dependencies = [
        ('carts', '0002_cart_subtotal'),
    ]

    operations = [
        migrations.CreateModel(
            name='Order',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('order_id', models.CharField(blank=True, max_length=120)),
                ('status', models.CharField(choices=[('created', 'Created'), ('paid', 'Paid'), ('shipped', 'Shipped'), ('refunded', 'Refunded')], default='created', max_length=120)),
                ('shipping_total', models.DecimalField(decimal_places=2, default=5.99, max_digits=100)),
                ('total', models.DecimalField(decimal_places=2, default=0.0, max_digits=100)),
                ('cart', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='carts.Cart')),
            ],
        ),
    ]


================================================
FILE: src/orders/migrations/0002_auto_20170928_2224.py
================================================
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-09-28 22:24
from __future__ import unicode_literals

from django.db import migrations, models
import django.db.models.deletion


class Migration
Download .txt
gitextract_e8nnqks8/

├── .gitignore
├── README.md
├── ecommerce.code-workspace
├── ecommerce.sublime-project
├── ecommerce.sublime-workspace
├── fasttracktojquery/
│   └── index.html
├── notes/
│   └── checkout_process.md
├── parse_git_log.py
├── pyvenv.cfg
├── src/
│   ├── .gitignore
│   ├── Procfile
│   ├── accounts/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── forms.py
│   │   ├── migrations/
│   │   │   ├── 0001_initial.py
│   │   │   ├── 0002_user_full_name.py
│   │   │   ├── 0003_user_is_active.py
│   │   │   ├── 0004_remove_user_active.py
│   │   │   ├── 0005_emailactivation.py
│   │   │   └── __init__.py
│   │   ├── models.py
│   │   ├── passwords/
│   │   │   ├── __init__.py
│   │   │   └── urls.py
│   │   ├── signals.py
│   │   ├── templates/
│   │   │   └── accounts/
│   │   │       ├── detail-update-view.html
│   │   │       ├── home.html
│   │   │       ├── login.html
│   │   │       ├── register.html
│   │   │       └── snippets/
│   │   │           └── form.html
│   │   ├── tests.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── addresses/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── forms.py
│   │   ├── migrations/
│   │   │   ├── 0001_initial.py
│   │   │   ├── 0002_auto_20171107_0055.py
│   │   │   └── __init__.py
│   │   ├── models.py
│   │   ├── templates/
│   │   │   └── addresses/
│   │   │       ├── form.html
│   │   │       ├── list.html
│   │   │       ├── prev_addresses.html
│   │   │       └── update.html
│   │   ├── tests.py
│   │   └── views.py
│   ├── analytics/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── migrations/
│   │   │   ├── 0001_initial.py
│   │   │   ├── 0002_usersession.py
│   │   │   └── __init__.py
│   │   ├── mixins.py
│   │   ├── models.py
│   │   ├── signals.py
│   │   ├── templates/
│   │   │   └── analytics/
│   │   │       └── sales.html
│   │   ├── tests.py
│   │   ├── utils.py
│   │   └── views.py
│   ├── billing/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── migrations/
│   │   │   ├── 0001_initial.py
│   │   │   ├── 0002_auto_20170928_2052.py
│   │   │   ├── 0003_billingprofile_customer_id.py
│   │   │   ├── 0004_card.py
│   │   │   ├── 0005_card_default.py
│   │   │   ├── 0006_charge.py
│   │   │   ├── 0007_auto_20171012_1935.py
│   │   │   └── __init__.py
│   │   ├── models.py
│   │   ├── templates/
│   │   │   └── billing/
│   │   │       └── payment-method.html
│   │   ├── tests.py
│   │   └── views.py
│   ├── carts/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── migrations/
│   │   │   ├── 0001_initial.py
│   │   │   ├── 0002_cart_subtotal.py
│   │   │   └── __init__.py
│   │   ├── models.py
│   │   ├── templates/
│   │   │   └── carts/
│   │   │       ├── checkout-done.html
│   │   │       ├── checkout.html
│   │   │       ├── home.html
│   │   │       └── snippets/
│   │   │           └── remove-product.html
│   │   ├── tests.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── db.sqlite3
│   ├── db2.sqlite3
│   ├── ecommerce/
│   │   ├── __init__.py
│   │   ├── aws/
│   │   │   ├── __init__.py
│   │   │   ├── conf.py
│   │   │   ├── download/
│   │   │   │   ├── __init__.py
│   │   │   │   └── utils.py
│   │   │   └── utils.py
│   │   ├── forms.py
│   │   ├── mixins.py
│   │   ├── settings/
│   │   │   ├── __init__.py
│   │   │   ├── base.py
│   │   │   ├── local.py
│   │   │   └── production.py
│   │   ├── urls.py
│   │   ├── utils.py
│   │   ├── views.py
│   │   └── wsgi.py
│   ├── manage.py
│   ├── marketing/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── forms.py
│   │   ├── migrations/
│   │   │   ├── 0001_initial.py
│   │   │   ├── 0002_marketingpreference_mailchimp_subscribed.py
│   │   │   ├── 0003_auto_20171018_0142.py
│   │   │   └── __init__.py
│   │   ├── mixins.py
│   │   ├── models.py
│   │   ├── tests.py
│   │   ├── utils.py
│   │   └── views.py
│   ├── orders/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── migrations/
│   │   │   ├── 0001_initial.py
│   │   │   ├── 0002_auto_20170928_2224.py
│   │   │   ├── 0003_auto_20170929_0013.py
│   │   │   ├── 0004_auto_20171025_2216.py
│   │   │   ├── 0005_auto_20171107_0035.py
│   │   │   ├── 0006_productpurchase_productpurchasemanager.py
│   │   │   ├── 0007_auto_20171108_0028.py
│   │   │   ├── 0008_delete_productpurchasemanager.py
│   │   │   └── __init__.py
│   │   ├── models.py
│   │   ├── templates/
│   │   │   └── orders/
│   │   │       ├── library.html
│   │   │       ├── order_detail.html
│   │   │       └── order_list.html
│   │   ├── tests.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── products/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── fixtures/
│   │   │   └── products.json
│   │   ├── migrations/
│   │   │   ├── 0001_initial.py
│   │   │   ├── 0002_product_price.py
│   │   │   ├── 0003_product_image.py
│   │   │   ├── 0004_auto_20170901_2159.py
│   │   │   ├── 0005_product_featured.py
│   │   │   ├── 0006_auto_20170901_2254.py
│   │   │   ├── 0007_auto_20170901_2254.py
│   │   │   ├── 0008_auto_20170901_2300.py
│   │   │   ├── 0009_product_timestamp.py
│   │   │   ├── 0010_product_is_digital.py
│   │   │   ├── 0011_productfile.py
│   │   │   ├── 0012_auto_20171108_2325.py
│   │   │   ├── 0013_auto_20171109_0023.py
│   │   │   ├── 0014_auto_20171116_0011.py
│   │   │   ├── 0015_productfile_name.py
│   │   │   └── __init__.py
│   │   ├── models.py
│   │   ├── templates/
│   │   │   └── products/
│   │   │       ├── detail.html
│   │   │       ├── featured-detail.html
│   │   │       ├── list.html
│   │   │       ├── snippets/
│   │   │       │   ├── card.html
│   │   │       │   └── update-cart.html
│   │   │       └── user-history.html
│   │   ├── tests.py
│   │   ├── understanding_crud.md
│   │   ├── urls.py
│   │   └── views.py
│   ├── requirements.txt
│   ├── runtime.txt
│   ├── search/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── migrations/
│   │   │   └── __init__.py
│   │   ├── models.py
│   │   ├── templates/
│   │   │   └── search/
│   │   │       ├── snippets/
│   │   │       │   └── search-form.html
│   │   │       └── view.html
│   │   ├── tests.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── static_my_proj/
│   │   ├── css/
│   │   │   ├── main.css
│   │   │   └── stripe-custom-style.css
│   │   └── js/
│   │       ├── csrf.ajax.js
│   │       ├── ecommerce.js
│   │       ├── ecommerce.main.js
│   │       └── ecommerce.sales.js
│   ├── tags/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── migrations/
│   │   │   ├── 0001_initial.py
│   │   │   └── __init__.py
│   │   ├── models.py
│   │   ├── shell_commands.py
│   │   ├── tests.py
│   │   └── views.py
│   └── templates/
│       ├── 400.html
│       ├── 403.html
│       ├── 404.html
│       ├── 500.html
│       ├── base/
│       │   ├── css.html
│       │   ├── forms.html
│       │   ├── js.html
│       │   ├── js_templates.html
│       │   └── navbar.html
│       ├── base.html
│       ├── bootstrap/
│       │   └── example.html
│       ├── contact/
│       │   └── view.html
│       ├── home_page.html
│       └── registration/
│           ├── activation-error.html
│           ├── emails/
│           │   ├── verify.html
│           │   └── verify.txt
│           ├── password_change_done.html
│           ├── password_change_form.html
│           ├── password_reset_complete.html
│           ├── password_reset_confirm.html
│           ├── password_reset_done.html
│           ├── password_reset_email.html
│           ├── password_reset_email.txt
│           └── password_reset_form.html
└── static_cdn/
    ├── media_root/
    │   └── products/
    │       └── 2473283945/
    │           └── 2473283945.sublime-project
    ├── protected_media/
    │   └── product/
    │       └── my-awesome-album/
    │           ├── basic_audio.m4a
    │           ├── basic_audio_5W1qjNh.m4a
    │           ├── basic_audio_5W1qjNh_Ntvw9l5.m4a
    │           ├── basic_audio_DwLL00o.m4a
    │           ├── basic_audio_uuyWQIO.m4a
    │           └── basic_audio_uuyWQIO_soaLtH9.m4a
    └── static_root/
        ├── admin/
        │   ├── css/
        │   │   ├── base.css
        │   │   ├── changelists.css
        │   │   ├── dashboard.css
        │   │   ├── fonts.css
        │   │   ├── forms.css
        │   │   ├── login.css
        │   │   ├── rtl.css
        │   │   └── widgets.css
        │   ├── fonts/
        │   │   ├── LICENSE.txt
        │   │   └── README.txt
        │   ├── img/
        │   │   ├── LICENSE
        │   │   └── README.txt
        │   └── js/
        │       ├── SelectBox.js
        │       ├── SelectFilter2.js
        │       ├── actions.js
        │       ├── admin/
        │       │   ├── DateTimeShortcuts.js
        │       │   └── RelatedObjectLookups.js
        │       ├── calendar.js
        │       ├── cancel.js
        │       ├── change_form.js
        │       ├── collapse.js
        │       ├── core.js
        │       ├── inlines.js
        │       ├── jquery.init.js
        │       ├── popup_response.js
        │       ├── prepopulate.js
        │       ├── prepopulate_init.js
        │       ├── timeparse.js
        │       ├── urlify.js
        │       └── vendor/
        │           ├── jquery/
        │           │   ├── LICENSE-JQUERY.txt
        │           │   └── jquery.js
        │           └── xregexp/
        │               ├── LICENSE-XREGEXP.txt
        │               └── xregexp.js
        ├── css/
        │   ├── main.css
        │   └── stripe-custom-style.css
        └── js/
            ├── csrf.ajax.js
            ├── ecommerce.js
            └── ecommerce.main.js
Download .txt
SYMBOL INDEX (490 symbols across 103 files)

FILE: src/accounts/admin.py
  class UserAdmin (line 15) | class UserAdmin(BaseUserAdmin):
  class EmailActivationAdmin (line 50) | class EmailActivationAdmin(admin.ModelAdmin):
    class Meta (line 52) | class Meta:
  class GuestEmailAdmin (line 59) | class GuestEmailAdmin(admin.ModelAdmin):
    class Meta (line 61) | class Meta:

FILE: src/accounts/apps.py
  class AccountsConfig (line 4) | class AccountsConfig(AppConfig):

FILE: src/accounts/forms.py
  class ReactivateEmailForm (line 12) | class ReactivateEmailForm(forms.Form):
    method clean_email (line 15) | def clean_email(self):
  class UserAdminCreationForm (line 26) | class UserAdminCreationForm(forms.ModelForm):
    class Meta (line 32) | class Meta:
    method clean_password2 (line 36) | def clean_password2(self):
    method save (line 44) | def save(self, commit=True):
  class UserDetailChangeForm (line 54) | class UserDetailChangeForm(forms.ModelForm):
    class Meta (line 57) | class Meta:
  class UserAdminChangeForm (line 63) | class UserAdminChangeForm(forms.ModelForm):
    class Meta (line 70) | class Meta:
    method clean_password (line 74) | def clean_password(self):
  class GuestForm (line 82) | class GuestForm(forms.ModelForm):
    class Meta (line 84) | class Meta:
    method __init__ (line 90) | def __init__(self, request, *args, **kwargs):
    method save (line 94) | def save(self, commit=True):
  class LoginForm (line 105) | class LoginForm(forms.Form):
    method __init__ (line 109) | def __init__(self, request, *args, **kwargs):
    method clean (line 113) | def clean(self):
  class RegisterForm (line 173) | class RegisterForm(forms.ModelForm):
    class Meta (line 179) | class Meta:
    method clean_password2 (line 183) | def clean_password2(self):
    method save (line 191) | def save(self, commit=True):

FILE: src/accounts/migrations/0001_initial.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/accounts/migrations/0002_user_full_name.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/accounts/migrations/0003_user_is_active.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/accounts/migrations/0004_remove_user_active.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/accounts/migrations/0005_emailactivation.py
  class Migration (line 10) | class Migration(migrations.Migration):

FILE: src/accounts/models.py
  class UserManager (line 20) | class UserManager(BaseUserManager):
    method create_user (line 21) | def create_user(self, email, full_name=None, password=None, is_active=...
    method create_staffuser (line 37) | def create_staffuser(self, email,full_name=None, password=None):
    method create_superuser (line 46) | def create_superuser(self, email, full_name=None, password=None):
  class User (line 57) | class User(AbstractBaseUser):
    method __str__ (line 73) | def __str__(self):
    method get_full_name (line 76) | def get_full_name(self):
    method get_short_name (line 81) | def get_short_name(self):
    method has_perm (line 84) | def has_perm(self, perm, obj=None):
    method has_module_perms (line 87) | def has_module_perms(self, app_label):
    method is_staff (line 91) | def is_staff(self):
    method is_admin (line 97) | def is_admin(self):
  class EmailActivationQuerySet (line 105) | class EmailActivationQuerySet(models.query.QuerySet):
    method confirmable (line 106) | def confirmable(self):
  class EmailActivationManager (line 120) | class EmailActivationManager(models.Manager):
    method get_queryset (line 121) | def get_queryset(self):
    method confirmable (line 124) | def confirmable(self):
    method email_exists (line 127) | def email_exists(self, email):
  class EmailActivation (line 136) | class EmailActivation(models.Model):
    method __str__ (line 148) | def __str__(self):
    method can_activate (line 151) | def can_activate(self):
    method activate (line 157) | def activate(self):
    method regenerate (line 169) | def regenerate(self):
    method send_activation (line 176) | def send_activation(self):
  function pre_save_email_activation (line 204) | def pre_save_email_activation(sender, instance, *args, **kwargs):
  function post_save_user_create_reciever (line 212) | def post_save_user_create_reciever(sender, instance, created, *args, **k...
  class GuestEmail (line 221) | class GuestEmail(models.Model):
    method __str__ (line 227) | def __str__(self):

FILE: src/accounts/views.py
  class AccountHomeView (line 26) | class AccountHomeView(LoginRequiredMixin, DetailView):
    method get_object (line 28) | def get_object(self):
  class AccountEmailActivateView (line 33) | class AccountEmailActivateView(FormMixin, View):
    method get (line 37) | def get(self, request, key=None, *args, **kwargs):
    method post (line 59) | def post(self, request, *args, **kwargs):
    method form_valid (line 67) | def form_valid(self, form):
    method form_invalid (line 78) | def form_invalid(self, form):
  class GuestRegisterView (line 83) | class GuestRegisterView(NextUrlMixin,  RequestFormAttachMixin, CreateView):
    method get_success_url (line 87) | def get_success_url(self):
    method form_invalid (line 90) | def form_invalid(self, form):
  class LoginView (line 94) | class LoginView(NextUrlMixin, RequestFormAttachMixin, FormView):
    method form_valid (line 100) | def form_valid(self, form):
  class RegisterView (line 107) | class RegisterView(CreateView):
  class UserDetailUpdateView (line 115) | class UserDetailUpdateView(LoginRequiredMixin, UpdateView):
    method get_object (line 119) | def get_object(self):
    method get_context_data (line 122) | def get_context_data(self, *args, **kwargs):
    method get_success_url (line 127) | def get_success_url(self):

FILE: src/addresses/apps.py
  class AddressesConfig (line 4) | class AddressesConfig(AppConfig):

FILE: src/addresses/forms.py
  class AddressForm (line 6) | class AddressForm(forms.ModelForm):
    class Meta (line 10) | class Meta:
  class AddressCheckoutForm (line 28) | class AddressCheckoutForm(forms.ModelForm):
    class Meta (line 32) | class Meta:

FILE: src/addresses/migrations/0001_initial.py
  class Migration (line 9) | class Migration(migrations.Migration):

FILE: src/addresses/migrations/0002_auto_20171107_0055.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/addresses/models.py
  class Address (line 10) | class Address(models.Model):
    method __str__ (line 22) | def __str__(self):
    method get_absolute_url (line 27) | def get_absolute_url(self):
    method get_short_address (line 30) | def get_short_address(self):
    method get_address (line 40) | def get_address(self):

FILE: src/addresses/views.py
  class AddressListView (line 13) | class AddressListView(LoginRequiredMixin, ListView):
    method get_queryset (line 16) | def get_queryset(self):
  class AddressUpdateView (line 23) | class AddressUpdateView(LoginRequiredMixin, UpdateView):
    method get_queryset (line 28) | def get_queryset(self):
  class AddressCreateView (line 34) | class AddressCreateView(LoginRequiredMixin, CreateView):
    method form_valid (line 39) | def form_valid(self, form):
  function checkout_address_create_view (line 56) | def checkout_address_create_view(request):
  function checkout_address_reuse_view (line 84) | def checkout_address_reuse_view(request):

FILE: src/analytics/apps.py
  class AnalyticsConfig (line 4) | class AnalyticsConfig(AppConfig):

FILE: src/analytics/migrations/0001_initial.py
  class Migration (line 10) | class Migration(migrations.Migration):

FILE: src/analytics/migrations/0002_usersession.py
  class Migration (line 10) | class Migration(migrations.Migration):

FILE: src/analytics/mixins.py
  class ObjectViewedMixin (line 4) | class ObjectViewedMixin(object):
    method get_context_data (line 5) | def get_context_data(self, *args, **kwargs):

FILE: src/analytics/models.py
  class ObjectViewedQuerySet (line 19) | class ObjectViewedQuerySet(models.query.QuerySet):
    method by_model (line 20) | def by_model(self, model_class, model_queryset=False):
  class ObjectViewedManager (line 28) | class ObjectViewedManager(models.Manager):
    method get_queryset (line 29) | def get_queryset(self):
    method by_model (line 32) | def by_model(self, model_class, model_queryset=False):
  class ObjectViewed (line 35) | class ObjectViewed(models.Model):
    method __str__ (line 45) | def __str__(self):
    class Meta (line 48) | class Meta:
  function object_viewed_receiver (line 54) | def object_viewed_receiver(sender, instance, request, *args, **kwargs):
  class UserSession (line 73) | class UserSession(models.Model):
    method end_session (line 81) | def end_session(self):
  function post_save_session_receiver (line 95) | def post_save_session_receiver(sender, instance, created, *args, **kwargs):
  function post_save_user_changed_receiver (line 107) | def post_save_user_changed_receiver(sender, instance, created, *args, **...
  function user_logged_in_receiver (line 120) | def user_logged_in_receiver(sender, instance, request, *args, **kwargs):

FILE: src/analytics/utils.py
  function get_client_ip (line 3) | def get_client_ip(request):

FILE: src/analytics/views.py
  class SalesAjaxView (line 14) | class SalesAjaxView(View):
    method get (line 15) | def get(self, request, *args, **kwargs):
  class SalesView (line 55) | class SalesView(LoginRequiredMixin, TemplateView):
    method dispatch (line 58) | def dispatch(self, *args, **kwargs):
    method get_context_data (line 65) | def get_context_data(self, *args, **kwargs):

FILE: src/billing/apps.py
  class BillingConfig (line 4) | class BillingConfig(AppConfig):

FILE: src/billing/migrations/0001_initial.py
  class Migration (line 10) | class Migration(migrations.Migration):

FILE: src/billing/migrations/0002_auto_20170928_2052.py
  class Migration (line 10) | class Migration(migrations.Migration):

FILE: src/billing/migrations/0003_billingprofile_customer_id.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/billing/migrations/0004_card.py
  class Migration (line 9) | class Migration(migrations.Migration):

FILE: src/billing/migrations/0005_card_default.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/billing/migrations/0006_charge.py
  class Migration (line 9) | class Migration(migrations.Migration):

FILE: src/billing/migrations/0007_auto_20171012_1935.py
  class Migration (line 9) | class Migration(migrations.Migration):

FILE: src/billing/models.py
  class BillingProfileManager (line 17) | class BillingProfileManager(models.Manager):
    method new_or_get (line 18) | def new_or_get(self, request):
  class BillingProfile (line 36) | class BillingProfile(models.Model):
    method __str__ (line 47) | def __str__(self):
    method charge (line 50) | def charge(self, order_obj, card=None):
    method get_cards (line 53) | def get_cards(self):
    method get_payment_method_url (line 56) | def get_payment_method_url(self):
    method has_card (line 60) | def has_card(self): # instance.has_card
    method default_card (line 65) | def default_card(self):
    method set_cards_inactive (line 71) | def set_cards_inactive(self):
  function billing_profile_created_receiver (line 76) | def billing_profile_created_receiver(sender, instance, *args, **kwargs):
  function user_created_receiver (line 88) | def user_created_receiver(sender, instance, created, *args, **kwargs):
  class CardManager (line 95) | class CardManager(models.Manager):
    method all (line 96) | def all(self, *args, **kwargs): # ModelKlass.objects.all() --> ModelKl...
    method add_new (line 99) | def add_new(self, billing_profile, token):
  class Card (line 117) | class Card(models.Model):
    method __str__ (line 131) | def __str__(self):
  function new_card_post_save_receiver (line 135) | def new_card_post_save_receiver(sender, instance, created, *args, **kwar...
  class ChargeManager (line 154) | class ChargeManager(models.Manager):
    method do (line 155) | def do(self, billing_profile, order_obj, card=None): # Charge.objects....
  class Charge (line 184) | class Charge(models.Model):

FILE: src/billing/views.py
  function payment_method_view (line 18) | def payment_method_view(request):
  function payment_method_createview (line 36) | def payment_method_createview(request):

FILE: src/carts/apps.py
  class CartsConfig (line 4) | class CartsConfig(AppConfig):

FILE: src/carts/migrations/0001_initial.py
  class Migration (line 10) | class Migration(migrations.Migration):

FILE: src/carts/migrations/0002_cart_subtotal.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/carts/models.py
  class CartManager (line 11) | class CartManager(models.Manager):
    method new_or_get (line 12) | def new_or_get(self, request):
    method new (line 27) | def new(self, user=None):
  class Cart (line 34) | class Cart(models.Model):
    method __str__ (line 44) | def __str__(self):
    method is_digital (line 48) | def is_digital(self):
  function m2m_changed_cart_receiver (line 58) | def m2m_changed_cart_receiver(sender, instance, action, *args, **kwargs):
  function pre_save_cart_receiver (line 73) | def pre_save_cart_receiver(sender, instance, *args, **kwargs):

FILE: src/carts/views.py
  function cart_detail_api_view (line 25) | def cart_detail_api_view(request):
  function cart_home (line 37) | def cart_home(request):
  function cart_update (line 42) | def cart_update(request):
  function checkout_home (line 73) | def checkout_home(request):
  function checkout_done_view (line 143) | def checkout_done_view(request):

FILE: src/ecommerce/aws/download/utils.py
  class AWSDownload (line 9) | class AWSDownload(object):
    method __init__ (line 16) | def __init__(self,  access_key, secret_key, bucket, region, *args, **k...
    method s3connect (line 23) | def s3connect(self):
    method get_bucket (line 33) | def get_bucket(self):
    method get_key (line 39) | def get_key(self, path):
    method get_filename (line 44) | def get_filename(self, path, new_filename=None):
    method generate_url (line 56) | def generate_url(self, path, download=True, new_filename=None):

FILE: src/ecommerce/forms.py
  class ContactForm (line 6) | class ContactForm(forms.Form):

FILE: src/ecommerce/mixins.py
  class RequestFormAttachMixin (line 4) | class RequestFormAttachMixin(object):
    method get_form_kwargs (line 5) | def get_form_kwargs(self):
  class NextUrlMixin (line 11) | class NextUrlMixin(object):
    method get_next_url (line 13) | def get_next_url(self):

FILE: src/ecommerce/utils.py
  function get_last_month_data (line 12) | def get_last_month_data(today):
  function get_month_data_range (line 23) | def get_month_data_range(months_ago=1, include_this_month=False):
  function get_filename (line 61) | def get_filename(path): #/abc/filename.mp4
  function random_string_generator (line 65) | def random_string_generator(size=10, chars=string.ascii_lowercase + stri...
  function unique_key_generator (line 69) | def unique_key_generator(instance):
  function unique_order_id_generator (line 83) | def unique_order_id_generator(instance):
  function unique_slug_generator (line 99) | def unique_slug_generator(instance, new_slug=None):

FILE: src/ecommerce/views.py
  function home_page (line 7) | def home_page(request):
  function about_page (line 19) | def about_page(request):
  function contact_page (line 26) | def contact_page(request):
  function home_page_old (line 54) | def home_page_old(request):

FILE: src/marketing/admin.py
  class MarketingPreferenceAdmin (line 5) | class MarketingPreferenceAdmin(admin.ModelAdmin):
    class Meta (line 8) | class Meta:

FILE: src/marketing/apps.py
  class MarketingConfig (line 4) | class MarketingConfig(AppConfig):

FILE: src/marketing/forms.py
  class MarketingPreferenceForm (line 6) | class MarketingPreferenceForm(forms.ModelForm):
    class Meta (line 8) | class Meta:

FILE: src/marketing/migrations/0001_initial.py
  class Migration (line 10) | class Migration(migrations.Migration):

FILE: src/marketing/migrations/0002_marketingpreference_mailchimp_subscribed.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/marketing/migrations/0003_auto_20171018_0142.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/marketing/mixins.py
  class CsrfExemptMixin (line 5) | class CsrfExemptMixin(object):
    method dispatch (line 7) | def dispatch(self, request, *args, **kwargs):

FILE: src/marketing/models.py
  class MarketingPreference (line 7) | class MarketingPreference(models.Model):
    method __str__ (line 15) | def __str__(self):
  function marketing_pref_create_receiver (line 21) | def marketing_pref_create_receiver(sender, instance, created, *args, **k...
  function marketing_pref_update_receiver (line 29) | def marketing_pref_update_receiver(sender, instance, *args, **kwargs):
  function make_marketing_pref_receiver (line 51) | def make_marketing_pref_receiver(sender, instance, created, *args, **kwa...

FILE: src/marketing/utils.py
  function check_email (line 14) | def check_email(email):
  function get_subscriber_hash (line 19) | def get_subscriber_hash(member_email):
  class Mailchimp (line 27) | class Mailchimp(object):
    method __init__ (line 28) | def __init__(self):
    method get_members_endpoint (line 41) | def get_members_endpoint(self):
    method change_subcription_status (line 44) | def change_subcription_status(self, email, status='unsubscribed'):
    method check_subcription_status (line 54) | def check_subcription_status(self, email):
    method check_valid_status (line 60) | def check_valid_status(self, status):
    method add_email (line 66) | def add_email(self, email):
    method unsubscribe (line 77) | def unsubscribe(self, email):
    method subscribe (line 80) | def subscribe(self, email):
    method pending (line 83) | def pending(self, email):

FILE: src/marketing/views.py
  class MarketingPreferenceUpdateView (line 15) | class MarketingPreferenceUpdateView(SuccessMessageMixin, UpdateView):
    method dispatch (line 21) | def dispatch(self, *args, **kwargs):
    method get_context_data (line 27) | def get_context_data(self, *args, **kwargs):
    method get_object (line 32) | def get_object(self):
  class MailchimpWebhookView (line 60) | class MailchimpWebhookView(CsrfExemptMixin, View): # HTTP GET -- def get...
    method post (line 63) | def post(self, request, *args, **kwargs):

FILE: src/orders/apps.py
  class OrdersConfig (line 4) | class OrdersConfig(AppConfig):

FILE: src/orders/migrations/0001_initial.py
  class Migration (line 9) | class Migration(migrations.Migration):

FILE: src/orders/migrations/0002_auto_20170928_2224.py
  class Migration (line 9) | class Migration(migrations.Migration):

FILE: src/orders/migrations/0003_auto_20170929_0013.py
  class Migration (line 9) | class Migration(migrations.Migration):

FILE: src/orders/migrations/0004_auto_20171025_2216.py
  class Migration (line 9) | class Migration(migrations.Migration):

FILE: src/orders/migrations/0005_auto_20171107_0035.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/orders/migrations/0006_productpurchase_productpurchasemanager.py
  class Migration (line 10) | class Migration(migrations.Migration):

FILE: src/orders/migrations/0007_auto_20171108_0028.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/orders/migrations/0008_delete_productpurchasemanager.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/orders/models.py
  class OrderManagerQuerySet (line 23) | class OrderManagerQuerySet(models.query.QuerySet):
    method recent (line 24) | def recent(self):
    method get_sales_breakdown (line 27) | def get_sales_breakdown(self):
    method by_weeks_range (line 46) | def by_weeks_range(self, weeks_ago=7, number_of_weeks=2):
    method by_range (line 55) | def by_range(self, start_date, end_date=None):
    method by_date (line 60) | def by_date(self):
    method totals_data (line 64) | def totals_data(self):
    method cart_data (line 67) | def cart_data(self):
    method by_status (line 74) | def by_status(self, status="shipped"):
    method not_refunded (line 77) | def not_refunded(self):
    method by_request (line 80) | def by_request(self, request):
    method not_created (line 84) | def not_created(self):
  class OrderManager (line 87) | class OrderManager(models.Manager):
    method get_queryset (line 88) | def get_queryset(self):
    method by_request (line 91) | def by_request(self, request):
    method new_or_get (line 94) | def new_or_get(self, billing_profile, cart_obj):
  class Order (line 114) | class Order(models.Model):
    method __str__ (line 129) | def __str__(self):
    class Meta (line 134) | class Meta:
    method get_absolute_url (line 137) | def get_absolute_url(self):
    method get_status (line 140) | def get_status(self):
    method update_total (line 147) | def update_total(self):
    method check_done (line 156) | def check_done(self):
    method update_purchases (line 172) | def update_purchases(self):
    method mark_paid (line 181) | def mark_paid(self):
  function pre_save_create_order_id (line 190) | def pre_save_create_order_id(sender, instance, *args, **kwargs):
  function post_save_cart_total (line 207) | def post_save_cart_total(sender, instance, created, *args, **kwargs):
  function post_save_order (line 220) | def post_save_order(sender, instance, created, *args, **kwargs):
  class ProductPurchaseQuerySet (line 231) | class ProductPurchaseQuerySet(models.query.QuerySet):
    method active (line 232) | def active(self):
    method digital (line 235) | def digital(self):
    method by_request (line 238) | def by_request(self, request):
  class ProductPurchaseManager (line 244) | class ProductPurchaseManager(models.Manager):
    method get_queryset (line 245) | def get_queryset(self):
    method all (line 248) | def all(self):
    method digital (line 251) | def digital(self):
    method by_request (line 254) | def by_request(self, request):
    method products_by_id (line 257) | def products_by_id(self, request):
    method products_by_request (line 262) | def products_by_request(self, request):
  class ProductPurchase (line 269) | class ProductPurchase(models.Model):
    method __str__ (line 279) | def __str__(self):

FILE: src/orders/views.py
  class OrderListView (line 10) | class OrderListView(LoginRequiredMixin, ListView):
    method get_queryset (line 12) | def get_queryset(self):
  class OrderDetailView (line 16) | class OrderDetailView(LoginRequiredMixin, DetailView):
    method get_object (line 18) | def get_object(self):
  class LibraryView (line 32) | class LibraryView(LoginRequiredMixin, ListView):
    method get_queryset (line 34) | def get_queryset(self):
  class VerifyOwnership (line 38) | class VerifyOwnership(View):
    method get (line 39) | def get(self, request, *args, **kwargs):

FILE: src/products/admin.py
  class ProductFileInline (line 6) | class ProductFileInline(admin.TabularInline):
  class ProductAdmin (line 11) | class ProductAdmin(admin.ModelAdmin):
    class Meta (line 14) | class Meta:

FILE: src/products/apps.py
  class ProductsConfig (line 4) | class ProductsConfig(AppConfig):

FILE: src/products/migrations/0001_initial.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/products/migrations/0002_product_price.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/products/migrations/0003_product_image.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/products/migrations/0004_auto_20170901_2159.py
  class Migration (line 9) | class Migration(migrations.Migration):

FILE: src/products/migrations/0005_product_featured.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/products/migrations/0006_auto_20170901_2254.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/products/migrations/0007_auto_20170901_2254.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/products/migrations/0008_auto_20170901_2300.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/products/migrations/0009_product_timestamp.py
  class Migration (line 9) | class Migration(migrations.Migration):

FILE: src/products/migrations/0010_product_is_digital.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/products/migrations/0011_productfile.py
  class Migration (line 9) | class Migration(migrations.Migration):

FILE: src/products/migrations/0012_auto_20171108_2325.py
  class Migration (line 10) | class Migration(migrations.Migration):

FILE: src/products/migrations/0013_auto_20171109_0023.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/products/migrations/0014_auto_20171116_0011.py
  class Migration (line 10) | class Migration(migrations.Migration):

FILE: src/products/migrations/0015_productfile_name.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/products/models.py
  function get_filename_ext (line 15) | def get_filename_ext(filepath):
  function upload_image_path (line 21) | def upload_image_path(instance, filename):
  class ProductQuerySet (line 32) | class ProductQuerySet(models.query.QuerySet):
    method active (line 33) | def active(self):
    method featured (line 36) | def featured(self):
    method search (line 39) | def search(self, query):
  class ProductManager (line 48) | class ProductManager(models.Manager):
    method get_queryset (line 49) | def get_queryset(self):
    method all (line 52) | def all(self):
    method featured (line 55) | def featured(self): #Product.objects.featured()
    method get_by_id (line 58) | def get_by_id(self, id):
    method search (line 64) | def search(self, query):
  class Product (line 68) | class Product(models.Model):
    method get_absolute_url (line 81) | def get_absolute_url(self):
    method __str__ (line 85) | def __str__(self):
    method __unicode__ (line 88) | def __unicode__(self):
    method name (line 92) | def name(self):
    method get_downloads (line 95) | def get_downloads(self):
  function product_pre_save_receiver (line 100) | def product_pre_save_receiver(sender, instance, *args, **kwargs):
  function upload_product_file_loc (line 107) | def upload_product_file_loc(instance, filename):
  class ProductFile (line 125) | class ProductFile(models.Model):
    method __str__ (line 137) | def __str__(self):
    method display_name (line 141) | def display_name(self):
    method get_default_url (line 147) | def get_default_url(self):
    method generate_download_url (line 150) | def generate_download_url(self):
    method get_download_url (line 163) | def get_download_url(self): # detail view

FILE: src/products/views.py
  class ProductFeaturedListView (line 15) | class ProductFeaturedListView(ListView):
    method get_queryset (line 18) | def get_queryset(self, *args, **kwargs):
  class ProductFeaturedDetailView (line 23) | class ProductFeaturedDetailView(ObjectViewedMixin, DetailView):
  class UserProductHistoryView (line 32) | class UserProductHistoryView(LoginRequiredMixin, ListView):
    method get_context_data (line 34) | def get_context_data(self, *args, **kwargs):
    method get_queryset (line 40) | def get_queryset(self, *args, **kwargs):
  class ProductListView (line 47) | class ProductListView(ListView):
    method get_context_data (line 55) | def get_context_data(self, *args, **kwargs):
    method get_queryset (line 61) | def get_queryset(self, *args, **kwargs):
  function product_list_view (line 66) | def product_list_view(request):
  class ProductDetailSlugView (line 75) | class ProductDetailSlugView(ObjectViewedMixin, DetailView):
    method get_context_data (line 79) | def get_context_data(self, *args, **kwargs):
    method get_object (line 85) | def get_object(self, *args, **kwargs):
  class ProductDownloadView (line 108) | class ProductDownloadView(View):
    method get (line 109) | def get(self, request, *args, **kwargs):
  class ProductDetailView (line 158) | class ProductDetailView(ObjectViewedMixin, DetailView):
    method get_context_data (line 162) | def get_context_data(self, *args, **kwargs):
    method get_object (line 168) | def get_object(self, *args, **kwargs):
  function product_detail_view (line 182) | def product_detail_view(request, pk=None, *args, **kwargs):

FILE: src/search/apps.py
  class SearchConfig (line 4) | class SearchConfig(AppConfig):

FILE: src/search/views.py
  class SearchProductView (line 5) | class SearchProductView(ListView):
    method get_context_data (line 8) | def get_context_data(self, *args, **kwargs):
    method get_queryset (line 15) | def get_queryset(self, *args, **kwargs):

FILE: src/static_my_proj/js/csrf.ajax.js
  function getCookie (line 3) | function getCookie(name) {
  function csrfSafeMethod (line 20) | function csrfSafeMethod(method) {

FILE: src/static_my_proj/js/ecommerce.js
  function displaySubmitting (line 9) | function displaySubmitting(submitBtn, defaultText, doSubmit){
  function displaySearching (line 90) | function displaySearching(){
  function perfomSearch (line 95) | function perfomSearch(){
  function getOwnedProduct (line 108) | function getOwnedProduct(productId, submitSpan){
  function refreshCart (line 192) | function refreshCart(){

FILE: src/static_my_proj/js/ecommerce.main.js
  function displayBtnStatus (line 147) | function displayBtnStatus(element, newHtml, newClasses, loadTime, timeout){
  function redirectToNext (line 167) | function redirectToNext(nextPath, timeoffset) {
  function stripeTokenHandler (line 176) | function stripeTokenHandler(nextUrl, token){

FILE: src/static_my_proj/js/ecommerce.sales.js
  function renderChart (line 3) | function renderChart(id, data, labels){
  function getSalesData (line 30) | function getSalesData(id, type){

FILE: src/tags/apps.py
  class TagsConfig (line 4) | class TagsConfig(AppConfig):

FILE: src/tags/migrations/0001_initial.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: src/tags/models.py
  class Tag (line 9) | class Tag(models.Model):
    method __str__ (line 16) | def __str__(self):
  function tag_pre_save_receiver (line 20) | def tag_pre_save_receiver(sender, instance, *args, **kwargs):

FILE: static_cdn/static_root/admin/js/SelectFilter2.js
  function findForm (line 9) | function findForm(node) {

FILE: static_cdn/static_root/admin/js/admin/RelatedObjectLookups.js
  function id_to_windowname (line 12) | function id_to_windowname(text) {
  function windowname_to_id (line 18) | function windowname_to_id(text) {
  function showAdminPopup (line 24) | function showAdminPopup(triggeringLink, name_regexp, add_popup) {
  function showRelatedObjectLookupPopup (line 40) | function showRelatedObjectLookupPopup(triggeringLink) {
  function dismissRelatedLookupPopup (line 44) | function dismissRelatedLookupPopup(win, chosenId) {
  function showRelatedObjectPopup (line 55) | function showRelatedObjectPopup(triggeringLink) {
  function updateRelatedObjectLinks (line 59) | function updateRelatedObjectLinks(triggeringLink) {
  function dismissAddRelatedObjectPopup (line 76) | function dismissAddRelatedObjectPopup(win, newId, newRepr) {
  function dismissChangeRelatedObjectPopup (line 101) | function dismissChangeRelatedObjectPopup(win, objId, newRepr, newId) {
  function dismissDeleteRelatedObjectPopup (line 114) | function dismissDeleteRelatedObjectPopup(win, objId) {

FILE: static_cdn/static_root/admin/js/calendar.js
  function calendarMonth (line 103) | function calendarMonth(y, m) {
  function Calendar (line 148) | function Calendar(div_id, callback, selected) {

FILE: static_cdn/static_root/admin/js/core.js
  function addEvent (line 8) | function addEvent(obj, evType, fn) {
  function removeEvent (line 21) | function removeEvent(obj, evType, fn) {
  function cancelEventPropagation (line 34) | function cancelEventPropagation(e) {
  function quickElement (line 46) | function quickElement() {
  function removeChildren (line 62) | function removeChildren(a) {
  function findPosX (line 73) | function findPosX(obj) {
  function findPosY (line 91) | function findPosY(obj) {
  function getStyle (line 237) | function getStyle(oElm, strCssRule) {

FILE: static_cdn/static_root/admin/js/timeparse.js
  function parseTimeString (line 93) | function parseTimeString(s) {

FILE: static_cdn/static_root/admin/js/urlify.js
  function downcode (line 144) | function downcode(slug) {
  function URLify (line 152) | function URLify(s, num_chars, allowUnicode) {

FILE: static_cdn/static_root/admin/js/vendor/jquery/jquery.js
  function isArrayLike (line 529) | function isArrayLike( obj ) {
  function Sizzle (line 738) | function Sizzle( selector, context, results, seed ) {
  function createCache (line 878) | function createCache() {
  function markFunction (line 896) | function markFunction( fn ) {
  function assert (line 905) | function assert( fn ) {
  function addHandle (line 927) | function addHandle( attrs, handler ) {
  function siblingCheck (line 942) | function siblingCheck( a, b ) {
  function createInputPseudo (line 969) | function createInputPseudo( type ) {
  function createButtonPseudo (line 980) | function createButtonPseudo( type ) {
  function createPositionalPseudo (line 991) | function createPositionalPseudo( fn ) {
  function testContext (line 1014) | function testContext( context ) {
  function setFilters (line 2059) | function setFilters() {}
  function toSelector (line 2130) | function toSelector( tokens ) {
  function addCombinator (line 2140) | function addCombinator( matcher, combinator, base ) {
  function elementMatcher (line 2198) | function elementMatcher( matchers ) {
  function multipleContexts (line 2212) | function multipleContexts( selector, contexts, results ) {
  function condense (line 2221) | function condense( unmatched, map, filter, context, xml ) {
  function setMatcher (line 2242) | function setMatcher( preFilter, selector, matcher, postFilter, postFinde...
  function matcherFromTokens (line 2335) | function matcherFromTokens( tokens ) {
  function matcherFromGroupMatchers (line 2393) | function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
  function winnow (line 2731) | function winnow( elements, qualifier, not ) {
  function sibling (line 3038) | function sibling( cur, dir ) {
  function createOptions (line 3114) | function createOptions( options ) {
  function completed (line 3549) | function completed() {
  function Data (line 3660) | function Data() {
  function dataAttr (line 3870) | function dataAttr( elem, key, data ) {
  function adjustCSS (line 4187) | function adjustCSS( elem, prop, valueParts, tween ) {
  function getAll (line 4276) | function getAll( context, tag ) {
  function setGlobalEval (line 4293) | function setGlobalEval( elems, refElements ) {
  function buildFragment (line 4309) | function buildFragment( elems, context, scripts, selection, ignored ) {
  function returnTrue (line 4430) | function returnTrue() {
  function returnFalse (line 4434) | function returnFalse() {
  function safeActiveElement (line 4440) | function safeActiveElement() {
  function on (line 4446) | function on( elem, types, selector, data, fn, one ) {
  function manipulationTarget (line 5137) | function manipulationTarget( elem, content ) {
  function disableScript (line 5147) | function disableScript( elem ) {
  function restoreScript (line 5151) | function restoreScript( elem ) {
  function cloneCopyEvent (line 5163) | function cloneCopyEvent( src, dest ) {
  function fixInput (line 5198) | function fixInput( src, dest ) {
  function domManip (line 5211) | function domManip( collection, args, callback, ignored ) {
  function remove (line 5301) | function remove( elem, selector, keepData ) {
  function actualDisplay (line 5592) | function actualDisplay( name, doc ) {
  function defaultDisplay (line 5608) | function defaultDisplay( nodeName ) {
  function computeStyleTests (line 5704) | function computeStyleTests() {
  function curCSS (line 5794) | function curCSS( elem, name, computed ) {
  function addGetHookIf (line 5844) | function addGetHookIf( conditionFn, hookFn ) {
  function vendorPropName (line 5881) | function vendorPropName( name ) {
  function setPositiveNumber (line 5900) | function setPositiveNumber( elem, value, subtract ) {
  function augmentWidthOrHeight (line 5912) | function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
  function getWidthOrHeight (line 5956) | function getWidthOrHeight( elem, name, extra ) {
  function showHide (line 6014) | function showHide( elements, show ) {
  function Tween (line 6353) | function Tween( elem, options, prop, end, easing ) {
  function createFxNow (line 6477) | function createFxNow() {
  function genFx (line 6485) | function genFx( type, includeWidth ) {
  function createTween (line 6505) | function createTween( value, prop, animation ) {
  function defaultPrefilter (line 6519) | function defaultPrefilter( elem, props, opts ) {
  function propFilter (line 6655) | function propFilter( props, specialEasing ) {
  function Animation (line 6692) | function Animation( elem, properties, options ) {
  function getClass (line 7381) | function getClass( elem ) {
  function addToPrefiltersOrTransports (line 8053) | function addToPrefiltersOrTransports( structure ) {
  function inspectPrefiltersOrTransports (line 8087) | function inspectPrefiltersOrTransports( structure, options, originalOpti...
  function ajaxExtend (line 8116) | function ajaxExtend( target, src ) {
  function ajaxHandleResponses (line 8136) | function ajaxHandleResponses( s, jqXHR, responses ) {
  function ajaxConvert (line 8194) | function ajaxConvert( s, response, jqXHR, isSuccess ) {
  function done (line 8699) | function done( status, nativeStatusText, responses, headers ) {
  function buildParams (line 8952) | function buildParams( prefix, obj, traditional, add ) {
  function getWindow (line 9518) | function getWindow( elem ) {

FILE: static_cdn/static_root/admin/js/vendor/xregexp/xregexp.js
  function augment (line 102) | function augment(regex, captureNames, isNative) {
  function getNativeFlags (line 120) | function getNativeFlags(regex) {
  function copy (line 139) | function copy(regex, addFlags, removeFlags) {
  function lastIndexOf (line 167) | function lastIndexOf(array, value) {
  function isType (line 187) | function isType(value, type) {
  function prepareOptions (line 197) | function prepareOptions(value) {
  function runTokens (line 219) | function runTokens(pattern, pos, scope, context) {
  function setExtensibility (line 255) | function setExtensibility(on) {
  function setNatives (line 265) | function setNatives(on) {
  function slug (line 1296) | function slug(name) {
  function expand (line 1301) | function expand(str) {
  function pad4 (line 1306) | function pad4(str) {
  function dec (line 1314) | function dec(hex) {
  function hex (line 1319) | function hex(dec) {
  function invert (line 1324) | function invert(range) {
  function cacheInversion (line 1348) | function cacheInversion(item) {
  function row (line 1874) | function row(value, name, start, end) {
  function deanchor (line 2064) | function deanchor(pattern) {
  function asXRegExp (line 2079) | function asXRegExp(value) {
  function extend (line 2217) | function extend(a, b) {

FILE: static_cdn/static_root/js/csrf.ajax.js
  function getCookie (line 3) | function getCookie(name) {
  function csrfSafeMethod (line 20) | function csrfSafeMethod(method) {

FILE: static_cdn/static_root/js/ecommerce.js
  function displaySubmitting (line 9) | function displaySubmitting(submitBtn, defaultText, doSubmit){
  function displaySearching (line 90) | function displaySearching(){
  function perfomSearch (line 95) | function perfomSearch(){
  function getOwnedProduct (line 108) | function getOwnedProduct(productId, submitSpan){
  function refreshCart (line 192) | function refreshCart(){

FILE: static_cdn/static_root/js/ecommerce.main.js
  function displayBtnStatus (line 147) | function displayBtnStatus(element, newHtml, newClasses, loadTime, timeout){
  function redirectToNext (line 167) | function redirectToNext(nextPath, timeoffset) {
  function stripeTokenHandler (line 176) | function stripeTokenHandler(nextUrl, token){
Condensed preview — 267 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (938K chars).
[
  {
    "path": ".gitignore",
    "chars": 1381,
    "preview": ".DS_STORE\n\n.env\nnotes/email-activation.py\nsrc/ecommerce/aws/ignore2.py\n\n# Virtualenv related\nbin/\ninclude/\npip-selfcheck"
  },
  {
    "path": "README.md",
    "chars": 17007,
    "preview": "# eCommerce\n\n[![eCommerce Logo](https://cfe2-static.s3-us-west-2.amazonaws.com/media/courses/ecommerce/images/ecommerce_"
  },
  {
    "path": "ecommerce.code-workspace",
    "chars": 60,
    "preview": "{\n\t\"folders\": [\n\t\t{\n\t\t\t\"path\": \".\"\n\t\t}\n\t],\n\t\"settings\": {}\n}"
  },
  {
    "path": "ecommerce.sublime-project",
    "chars": 45,
    "preview": "{\n\t\"folders\":\n\t[\n\t\t{\n\t\t\t\"path\": \".\"\n\t\t}\n\t]\n}\n"
  },
  {
    "path": "ecommerce.sublime-workspace",
    "chars": 18631,
    "preview": "{\n\t\"auto_complete\":\n\t{\n\t\t\"selected_items\":\n\t\t[\n\t\t\t[\n\t\t\t\t\"pos\",\n\t\t\t\t\"postal_code\"\n\t\t\t],\n\t\t\t[\n\t\t\t\t\"add\",\n\t\t\t\t\"address_line"
  },
  {
    "path": "fasttracktojquery/index.html",
    "chars": 7713,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <!-- Required meta tags -->\n    <meta charset=\"utf-8\">\n    <meta name=\"vie"
  },
  {
    "path": "notes/checkout_process.md",
    "chars": 622,
    "preview": "# Checkout Process\n\n1. Cart -> Checkout View\n    ?\n    - Login/Register or Enter an Email (as Guest)\n    - Shipping Addr"
  },
  {
    "path": "parse_git_log.py",
    "chars": 602,
    "preview": "'''\nThis document helps use parse our git commits so we \ncan make them more easily readable and clickable\nin our Readme."
  },
  {
    "path": "pyvenv.cfg",
    "chars": 114,
    "preview": "home = /Library/Frameworks/Python.framework/Versions/3.8/bin\ninclude-system-site-packages = false\nversion = 3.8.2\n"
  },
  {
    "path": "src/.gitignore",
    "chars": 1459,
    "preview": "# Not Ready for Production\n# marketing/\n\n.env\n\n\necommerce/settings/local.py\necommerce/aws/ignore2.py\n\n.DS_STORE\n*.sublim"
  },
  {
    "path": "src/Procfile",
    "chars": 28,
    "preview": "web: gunicorn ecommerce.wsgi"
  },
  {
    "path": "src/accounts/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/accounts/admin.py",
    "chars": 1802,
    "preview": "from django.contrib import admin\nfrom django.contrib.auth import get_user_model\nfrom django.contrib.auth.models import G"
  },
  {
    "path": "src/accounts/apps.py",
    "chars": 91,
    "preview": "from django.apps import AppConfig\n\n\nclass AccountsConfig(AppConfig):\n    name = 'accounts'\n"
  },
  {
    "path": "src/accounts/forms.py",
    "chars": 7506,
    "preview": "from django import forms\nfrom django.contrib.auth import authenticate, login, get_user_model\nfrom django.contrib.auth.fo"
  },
  {
    "path": "src/accounts/migrations/0001_initial.py",
    "chars": 1577,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-10-09 21:27\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/accounts/migrations/0002_user_full_name.py",
    "chars": 464,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-10-09 21:44\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/accounts/migrations/0003_user_is_active.py",
    "chars": 449,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-10-23 22:47\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/accounts/migrations/0004_remove_user_active.py",
    "chars": 388,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-10-24 17:09\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/accounts/migrations/0005_emailactivation.py",
    "chars": 1195,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-10-24 18:13\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/accounts/migrations/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/accounts/models.py",
    "chars": 7476,
    "preview": "from datetime import timedelta\nfrom django.conf import settings\nfrom django.core.urlresolvers import reverse\nfrom django"
  },
  {
    "path": "src/accounts/passwords/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/accounts/passwords/urls.py",
    "chars": 1075,
    "preview": "# accounts.passwords.urls.py \nfrom django.conf.urls import url\nfrom django.contrib.auth import views as auth_views\n\nurlp"
  },
  {
    "path": "src/accounts/signals.py",
    "chars": 100,
    "preview": "from django.dispatch import Signal\n\n\nuser_logged_in = Signal(providing_args=['instance', 'request'])"
  },
  {
    "path": "src/accounts/templates/accounts/detail-update-view.html",
    "chars": 722,
    "preview": "{% extends \"base.html\" %}\n\n\n{% block content %}\n<div class='col-12 col-md-6 mx-auto'>\n{% if title %}<h1 class='my-3'>{{ "
  },
  {
    "path": "src/accounts/templates/accounts/home.html",
    "chars": 2263,
    "preview": "{% extends \"base.html\" %}\n\n{% block content %}\n<div class='row'>\n<div class='col-12'>\n<h1>Account</h1>\n<hr/>\n</div>\n<div"
  },
  {
    "path": "src/accounts/templates/accounts/login.html",
    "chars": 216,
    "preview": "{% extends \"base.html\" %}\n\n{% block content %}\n<h1>Login</h1>\n    <form method='POST'> {% csrf_token %}\n      {{ form }}"
  },
  {
    "path": "src/accounts/templates/accounts/register.html",
    "chars": 223,
    "preview": "{% extends \"base.html\" %}\n\n{% block content %}\n    <h1>Register</h1>\n    <form method='POST'> {% csrf_token %}\n      {{ "
  },
  {
    "path": "src/accounts/templates/accounts/snippets/form.html",
    "chars": 306,
    "preview": "<form method='POST' action='{% if action_url %}{{ action_url }}{% else %}{% url \"login\" %}{% endif %}'> {% csrf_token %}"
  },
  {
    "path": "src/accounts/tests.py",
    "chars": 60,
    "preview": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "src/accounts/urls.py",
    "chars": 767,
    "preview": "from django.conf.urls import url\n\nfrom products.views import UserProductHistoryView\nfrom .views import (\n        Account"
  },
  {
    "path": "src/accounts/views.py",
    "chars": 5771,
    "preview": "from django.contrib.auth import authenticate, login, get_user_model\nfrom django.contrib.auth.decorators import login_req"
  },
  {
    "path": "src/addresses/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/addresses/admin.py",
    "chars": 91,
    "preview": "from django.contrib import admin\n\nfrom .models import Address\n\nadmin.site.register(Address)"
  },
  {
    "path": "src/addresses/apps.py",
    "chars": 93,
    "preview": "from django.apps import AppConfig\n\n\nclass AddressesConfig(AppConfig):\n    name = 'addresses'\n"
  },
  {
    "path": "src/addresses/forms.py",
    "chars": 893,
    "preview": "from django import forms\n\nfrom .models import Address\n\n\nclass AddressForm(forms.ModelForm):\n    \"\"\"\n    User-related CRU"
  },
  {
    "path": "src/addresses/migrations/0001_initial.py",
    "chars": 1281,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-28 23:42\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/addresses/migrations/0002_auto_20171107_0055.py",
    "chars": 960,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-11-07 00:55\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/addresses/migrations/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/addresses/models.py",
    "chars": 1997,
    "preview": "from django.db import models\nfrom django.core.urlresolvers import reverse\nfrom billing.models import BillingProfile\n\nADD"
  },
  {
    "path": "src/addresses/templates/addresses/form.html",
    "chars": 429,
    "preview": "<form method='POST' action='{% if action_url %}{{ action_url }}{% else %}{% url \"login\" %}{% endif %}'> {% csrf_token %}"
  },
  {
    "path": "src/addresses/templates/addresses/list.html",
    "chars": 998,
    "preview": "{% extends \"base.html\" %}\n\n{% block content %}\n<div class='row'>\n<div class='col-12'>\n<h1>Address{% if object_list.count"
  },
  {
    "path": "src/addresses/templates/addresses/prev_addresses.html",
    "chars": 798,
    "preview": "{% if address_qs.exists %}\n        <form method='POST' action='{{ action_url }}'> {% csrf_token %}\n             {% if ne"
  },
  {
    "path": "src/addresses/templates/addresses/update.html",
    "chars": 492,
    "preview": "{% extends \"base.html\" %}\n\n{% block content %}\n\n<div class='row'>\n    <div class='col-10 mx-auto col-md-6 '>\n        {% "
  },
  {
    "path": "src/addresses/tests.py",
    "chars": 60,
    "preview": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "src/addresses/views.py",
    "chars": 3728,
    "preview": "from django.contrib.auth.mixins import LoginRequiredMixin\nfrom django.views.generic import ListView, UpdateView, CreateV"
  },
  {
    "path": "src/analytics/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/analytics/admin.py",
    "chars": 149,
    "preview": "from django.contrib import admin\n\nfrom .models import ObjectViewed, UserSession\n\n\nadmin.site.register(ObjectViewed)\n\nadm"
  },
  {
    "path": "src/analytics/apps.py",
    "chars": 93,
    "preview": "from django.apps import AppConfig\n\n\nclass AnalyticsConfig(AppConfig):\n    name = 'analytics'\n"
  },
  {
    "path": "src/analytics/migrations/0001_initial.py",
    "chars": 1370,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-10-10 21:30\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/analytics/migrations/0002_usersession.py",
    "chars": 1167,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-10-10 22:08\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/analytics/migrations/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/analytics/mixins.py",
    "chars": 419,
    "preview": "from .signals import object_viewed_signal\n\n\nclass ObjectViewedMixin(object):\n    def get_context_data(self, *args, **kwa"
  },
  {
    "path": "src/analytics/models.py",
    "chars": 4692,
    "preview": "from django.conf import settings\nfrom django.contrib.contenttypes.fields import GenericForeignKey\nfrom django.contrib.co"
  },
  {
    "path": "src/analytics/signals.py",
    "chars": 106,
    "preview": "from django.dispatch import Signal\n\n\nobject_viewed_signal = Signal(providing_args=['instance', 'request'])"
  },
  {
    "path": "src/analytics/templates/analytics/sales.html",
    "chars": 1672,
    "preview": "{% extends \"base.html\" %}\n\n\n{% block content %}\n\n\n<div class='row my-5'>\n    <div class='col-12'>\n        <h1>Sales Data"
  },
  {
    "path": "src/analytics/tests.py",
    "chars": 60,
    "preview": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "src/analytics/utils.py",
    "chars": 234,
    "preview": "\n\ndef get_client_ip(request):\n    x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')\n    if x_forwarded_for:\n   "
  },
  {
    "path": "src/analytics/views.py",
    "chars": 3110,
    "preview": "import random\nimport datetime\nfrom django.contrib.auth.mixins import LoginRequiredMixin\nfrom django.db.models import Cou"
  },
  {
    "path": "src/billing/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/billing/admin.py",
    "chars": 175,
    "preview": "from django.contrib import admin\n\nfrom .models import BillingProfile, Card, Charge\n\nadmin.site.register(BillingProfile)\n"
  },
  {
    "path": "src/billing/apps.py",
    "chars": 89,
    "preview": "from django.apps import AppConfig\n\n\nclass BillingConfig(AppConfig):\n    name = 'billing'\n"
  },
  {
    "path": "src/billing/migrations/0001_initial.py",
    "chars": 1049,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-28 20:50\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/billing/migrations/0002_auto_20170928_2052.py",
    "chars": 598,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-28 20:52\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/billing/migrations/0003_billingprofile_customer_id.py",
    "chars": 486,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-10-11 19:13\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/billing/migrations/0004_card.py",
    "chars": 1153,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-10-11 22:08\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/billing/migrations/0005_card_default.py",
    "chars": 436,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-10-11 22:10\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/billing/migrations/0006_charge.py",
    "chars": 1212,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-10-12 00:06\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/billing/migrations/0007_auto_20171012_1935.py",
    "chars": 697,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-10-12 19:35\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/billing/migrations/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/billing/models.py",
    "chars": 7607,
    "preview": "from django.conf import settings\nfrom django.db import models\nfrom django.db.models.signals import post_save, pre_save\nf"
  },
  {
    "path": "src/billing/templates/billing/payment-method.html",
    "chars": 307,
    "preview": "{% extends 'base.html' %}\n\n\n{% block content %}\n\n<div class='col-10 col-md-6 mx-auto'>\n    <h1>Add Payment Method</h1>\n "
  },
  {
    "path": "src/billing/tests.py",
    "chars": 60,
    "preview": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "src/billing/views.py",
    "chars": 1636,
    "preview": "from django.conf import settings\nfrom django.http import JsonResponse, HttpResponse\nfrom django.shortcuts import render,"
  },
  {
    "path": "src/carts/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/carts/admin.py",
    "chars": 86,
    "preview": "from django.contrib import admin\n\n\nfrom .models import Cart\n\nadmin.site.register(Cart)"
  },
  {
    "path": "src/carts/apps.py",
    "chars": 85,
    "preview": "from django.apps import AppConfig\n\n\nclass CartsConfig(AppConfig):\n    name = 'carts'\n"
  },
  {
    "path": "src/carts/migrations/0001_initial.py",
    "chars": 1134,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-26 00:27\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/carts/migrations/0002_cart_subtotal.py",
    "chars": 471,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-26 01:23\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/carts/migrations/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/carts/models.py",
    "chars": 2551,
    "preview": "from decimal import Decimal\nfrom django.conf import settings\nfrom django.db import models\nfrom django.db.models.signals "
  },
  {
    "path": "src/carts/templates/carts/checkout-done.html",
    "chars": 172,
    "preview": "{% extends \"base.html\" %}\n\n\n{% block content %}\n<div class='col-6 mx-auto py-5 text-center'>\n  <h1 class='display-1'>Tha"
  },
  {
    "path": "src/carts/templates/carts/checkout.html",
    "chars": 3590,
    "preview": "{% extends \"base.html\" %}\n\n\n{% block content %}\n{% if not billing_profile %}\n    <div class='row text-center'>\n    <div "
  },
  {
    "path": "src/carts/templates/carts/home.html",
    "chars": 1245,
    "preview": "{% extends \"base.html\" %}\n\n\n{% block content %}\n<h1>Cart</h1>\n\n{% if cart.products.exists %}\n<table class=\"table cart-ta"
  },
  {
    "path": "src/carts/templates/carts/snippets/remove-product.html",
    "chars": 379,
    "preview": "<form class='form-product-ajax' method='POST' action='{% url \"cart:update\" %}' data-endpoint='{% url \"cart:update\" %}' c"
  },
  {
    "path": "src/carts/tests.py",
    "chars": 60,
    "preview": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "src/carts/urls.py",
    "chars": 392,
    "preview": "from django.conf.urls import url\n\nfrom .views import (\n        cart_home, \n        cart_update, \n        checkout_home,\n"
  },
  {
    "path": "src/carts/views.py",
    "chars": 5135,
    "preview": "from django.conf import settings\nfrom django.http import JsonResponse\nfrom django.shortcuts import render, redirect\n\n\nfr"
  },
  {
    "path": "src/ecommerce/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/ecommerce/aws/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/ecommerce/aws/conf.py",
    "chars": 1369,
    "preview": "import datetime\nimport os\n\ntry:\n    from .ignore2 import AWS_ACCESS_KEY_ID,  AWS_SECRET_ACCESS_KEY\nexcept:\n    AWS_ACCES"
  },
  {
    "path": "src/ecommerce/aws/download/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/ecommerce/aws/download/utils.py",
    "chars": 2478,
    "preview": "import boto\nimport re\nimport os\n\nfrom django.conf import settings\nfrom boto.s3.connection import OrdinaryCallingFormat\n\n"
  },
  {
    "path": "src/ecommerce/aws/utils.py",
    "chars": 255,
    "preview": "from storages.backends.s3boto3 import S3Boto3Storage\n\nStaticRootS3BotoStorage = lambda: S3Boto3Storage(location='static'"
  },
  {
    "path": "src/ecommerce/forms.py",
    "chars": 1206,
    "preview": "from django import forms\nfrom django.contrib.auth import get_user_model\n\nUser = get_user_model()\n\nclass ContactForm(form"
  },
  {
    "path": "src/ecommerce/mixins.py",
    "chars": 623,
    "preview": "from django.utils.http import is_safe_url\n\n\nclass RequestFormAttachMixin(object):\n    def get_form_kwargs(self):\n       "
  },
  {
    "path": "src/ecommerce/settings/__init__.py",
    "chars": 149,
    "preview": "from .base import *\n\nfrom .production import *\n\ntry:\n    from .local import *\nexcept:\n    pass\n\ntry:\n    from .local_jus"
  },
  {
    "path": "src/ecommerce/settings/base.py",
    "chars": 4919,
    "preview": "\"\"\"\nDjango settings for ecommerce project.\n\nGenerated by 'django-admin startproject' using Django 1.11.4.\n\nFor more info"
  },
  {
    "path": "src/ecommerce/settings/local.py",
    "chars": 5105,
    "preview": "\"\"\"\nDjango settings for ecommerce project.\n\nGenerated by 'django-admin startproject' using Django 1.11.4.\n\nFor more info"
  },
  {
    "path": "src/ecommerce/settings/production.py",
    "chars": 5324,
    "preview": "\"\"\"\nDjango settings for ecommerce project.\n\nGenerated by 'django-admin startproject' using Django 1.11.4.\n\nFor more info"
  },
  {
    "path": "src/ecommerce/urls.py",
    "chars": 4043,
    "preview": "\"\"\"ecommerce URL Configuration\n\nThe `urlpatterns` list routes URLs to views. For more information please see:\n    https:"
  },
  {
    "path": "src/ecommerce/utils.py",
    "chars": 3473,
    "preview": "\nimport datetime \nimport os\nimport random\nimport string\n\nfrom django.utils import timezone\nfrom django.utils.text import"
  },
  {
    "path": "src/ecommerce/views.py",
    "chars": 2996,
    "preview": "from django.contrib.auth import authenticate, login, get_user_model\nfrom django.http import HttpResponse, JsonResponse\nf"
  },
  {
    "path": "src/ecommerce/wsgi.py",
    "chars": 396,
    "preview": "\"\"\"\nWSGI config for ecommerce project.\n\nIt exposes the WSGI callable as a module-level variable named ``application``.\n\n"
  },
  {
    "path": "src/manage.py",
    "chars": 807,
    "preview": "#!/usr/bin/env python\nimport os\nimport sys\n\nif __name__ == \"__main__\":\n    os.environ.setdefault(\"DJANGO_SETTINGS_MODULE"
  },
  {
    "path": "src/marketing/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/marketing/admin.py",
    "chars": 636,
    "preview": "from django.contrib import admin\n\nfrom .models import MarketingPreference\n\nclass MarketingPreferenceAdmin(admin.ModelAdm"
  },
  {
    "path": "src/marketing/apps.py",
    "chars": 93,
    "preview": "from django.apps import AppConfig\n\n\nclass MarketingConfig(AppConfig):\n    name = 'marketing'\n"
  },
  {
    "path": "src/marketing/forms.py",
    "chars": 307,
    "preview": "from django import forms\n\nfrom .models import MarketingPreference\n\n\nclass MarketingPreferenceForm(forms.ModelForm):\n    "
  },
  {
    "path": "src/marketing/migrations/0001_initial.py",
    "chars": 1039,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-10-18 00:36\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/marketing/migrations/0002_marketingpreference_mailchimp_subscribed.py",
    "chars": 461,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-10-18 01:34\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/marketing/migrations/0003_auto_20171018_0142.py",
    "chars": 466,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-10-18 01:42\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/marketing/migrations/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/marketing/mixins.py",
    "chars": 304,
    "preview": "from django.utils.decorators import method_decorator\nfrom django.views.decorators.csrf import csrf_exempt\n\n\nclass CsrfEx"
  },
  {
    "path": "src/marketing/models.py",
    "chars": 2102,
    "preview": "from django.conf import settings\nfrom django.db import models\nfrom django.db.models.signals import post_save, pre_save\n\n"
  },
  {
    "path": "src/marketing/tests.py",
    "chars": 60,
    "preview": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "src/marketing/utils.py",
    "chars": 2872,
    "preview": "import hashlib\nimport json\nimport re\nimport requests\nfrom django.conf import settings\n\n\nMAILCHIMP_API_KEY = getattr(sett"
  },
  {
    "path": "src/marketing/views.py",
    "chars": 4165,
    "preview": "from django.conf import settings\n\nfrom django.contrib.messages.views import SuccessMessageMixin\nfrom django.http import "
  },
  {
    "path": "src/orders/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/orders/admin.py",
    "chars": 142,
    "preview": "from django.contrib import admin\n\nfrom .models import Order, ProductPurchase\n\nadmin.site.register(Order)\n\nadmin.site.reg"
  },
  {
    "path": "src/orders/apps.py",
    "chars": 87,
    "preview": "from django.apps import AppConfig\n\n\nclass OrdersConfig(AppConfig):\n    name = 'orders'\n"
  },
  {
    "path": "src/orders/migrations/0001_initial.py",
    "chars": 1130,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-27 23:00\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/orders/migrations/0002_auto_20170928_2224.py",
    "chars": 761,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-28 22:24\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/orders/migrations/0003_auto_20170929_0013.py",
    "chars": 909,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-29 00:13\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/orders/migrations/0004_auto_20171025_2216.py",
    "chars": 850,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-10-25 22:16\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/orders/migrations/0005_auto_20171107_0035.py",
    "chars": 644,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-11-07 00:35\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/orders/migrations/0006_productpurchase_productpurchasemanager.py",
    "chars": 1586,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-11-08 00:17\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/orders/migrations/0007_auto_20171108_0028.py",
    "chars": 644,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-11-08 00:28\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/orders/migrations/0008_delete_productpurchasemanager.py",
    "chars": 375,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-11-08 00:39\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/orders/migrations/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/orders/models.py",
    "chars": 9818,
    "preview": "import math\nimport datetime\nfrom django.conf import settings\nfrom django.db import models\nfrom django.db.models import C"
  },
  {
    "path": "src/orders/templates/orders/library.html",
    "chars": 944,
    "preview": "{% extends \"base.html\" %}\n\n\n{% block content %}\n\n\n<div class='row'>\n    <div class='col-12'>\n        <h1>Library</h1>\n  "
  },
  {
    "path": "src/orders/templates/orders/order_detail.html",
    "chars": 697,
    "preview": "{% extends \"base.html\" %}\n\n\n{% block content %}\n\n\n\n\n\n <div class='row'>\n    <div class='col-12 col-md-6 mx-auto'>\n      "
  },
  {
    "path": "src/orders/templates/orders/order_list.html",
    "chars": 815,
    "preview": "{% extends \"base.html\" %}\n\n\n{% block content %}\n\n\n<div class='row'>\n    <div class='col-12'>\n        <h1>Orders</h1>\n   "
  },
  {
    "path": "src/orders/tests.py",
    "chars": 60,
    "preview": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "src/orders/urls.py",
    "chars": 389,
    "preview": "from django.conf.urls import url\n\nfrom .views import (\n        OrderListView, \n        OrderDetailView,\n        VerifyOw"
  },
  {
    "path": "src/orders/views.py",
    "chars": 1679,
    "preview": "from django.contrib.auth.mixins import LoginRequiredMixin\nfrom django.http import Http404, JsonResponse\nfrom django.view"
  },
  {
    "path": "src/products/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/products/admin.py",
    "chars": 371,
    "preview": "from django.contrib import admin\n\nfrom .models import Product, ProductFile\n\n\nclass ProductFileInline(admin.TabularInline"
  },
  {
    "path": "src/products/apps.py",
    "chars": 91,
    "preview": "from django.apps import AppConfig\n\n\nclass ProductsConfig(AppConfig):\n    name = 'products'\n"
  },
  {
    "path": "src/products/fixtures/products.json",
    "chars": 20368,
    "preview": "[\n{\n    \"model\": \"products.product\",\n    \"pk\": 1,\n    \"fields\": {\n        \"title\": \"T-Shirt\",\n        \"slug\": \"t-shirt\","
  },
  {
    "path": "src/products/migrations/0001_initial.py",
    "chars": 606,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-01 19:03\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/products/migrations/0002_product_price.py",
    "chars": 475,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-01 19:07\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/products/migrations/0003_product_image.py",
    "chars": 476,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-01 21:48\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/products/migrations/0004_auto_20170901_2159.py",
    "chars": 524,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-01 21:59\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/products/migrations/0005_product_featured.py",
    "chars": 456,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-01 22:39\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/products/migrations/0006_auto_20170901_2254.py",
    "chars": 637,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-01 22:54\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/products/migrations/0007_auto_20170901_2254.py",
    "chars": 448,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-01 22:54\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/products/migrations/0008_auto_20170901_2300.py",
    "chars": 461,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-01 23:00\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/products/migrations/0009_product_timestamp.py",
    "chars": 562,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-18 19:28\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/products/migrations/0010_product_is_digital.py",
    "chars": 457,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-11-07 22:47\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/products/migrations/0011_productfile.py",
    "chars": 741,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-11-08 23:07\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/products/migrations/0012_auto_20171108_2325.py",
    "chars": 657,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-11-08 23:25\nfrom __future__ import unicode_literals\n\nimport"
  },
  {
    "path": "src/products/migrations/0013_auto_20171109_0023.py",
    "chars": 622,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-11-09 00:23\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/products/migrations/0014_auto_20171116_0011.py",
    "chars": 619,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-11-16 00:11\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/products/migrations/0015_productfile_name.py",
    "chars": 477,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.6 on 2017-11-16 00:12\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/products/migrations/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/products/models.py",
    "chars": 5778,
    "preview": "import random\nimport os\nfrom django.conf import settings\nfrom django.core.files.storage import FileSystemStorage\n\nfrom d"
  },
  {
    "path": "src/products/templates/products/detail.html",
    "chars": 591,
    "preview": "{% extends \"base.html\" %}\n\n\n{% block content %}\n\n\n    <div class='row'>\n        <div class='col-12 col-md-6'>\n          "
  },
  {
    "path": "src/products/templates/products/featured-detail.html",
    "chars": 148,
    "preview": "{{ object.title }} <br/>\n{{ object.description }} <br/>\n{% if object.image %}\n    <img src='{{ object.image.url }}' clas"
  },
  {
    "path": "src/products/templates/products/list.html",
    "chars": 272,
    "preview": "{% extends \"base.html\" %}\n\n{% block content %}\n        <div class='row'>\n\n    {% for obj in object_list %}\n        <div "
  },
  {
    "path": "src/products/templates/products/snippets/card.html",
    "chars": 737,
    "preview": "<div class=\"card\" style=\"width: 20rem;\">\n  {% if instance.image %}\n    <a href=\"{{ instance.get_absolute_url }}\"><img cl"
  },
  {
    "path": "src/products/templates/products/snippets/update-cart.html",
    "chars": 695,
    "preview": "<form class='form-product-ajax' method='POST' action='{% url \"cart:update\" %}' data-endpoint='{% url \"cart:update\" %}' c"
  },
  {
    "path": "src/products/templates/products/user-history.html",
    "chars": 435,
    "preview": "{% extends \"base.html\" %}\n\n{% block content %}\n        <div class='row'>\n            <div class='col-12 my-3'>\n         "
  },
  {
    "path": "src/products/tests.py",
    "chars": 60,
    "preview": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "src/products/understanding_crud.md",
    "chars": 118,
    "preview": "### Understanding CRUD\n\n\nCreate -- POST\nRetrieve / List / Search -- GET\nUpdate -- PUT / Patch / POST\nDelete -- Delete\n"
  },
  {
    "path": "src/products/urls.py",
    "chars": 401,
    "preview": "from django.conf.urls import url\n\nfrom .views import (\n        ProductListView, \n        ProductDetailSlugView, \n       "
  },
  {
    "path": "src/products/views.py",
    "chars": 7163,
    "preview": "# from django.views import ListView\nfrom django.contrib import messages\nfrom django.contrib.auth.mixins import LoginRequ"
  },
  {
    "path": "src/requirements.txt",
    "chars": 408,
    "preview": "boto3==1.4.7\nboto==2.48.0\nbotocore==1.7.32\ncertifi==2017.7.27.1\nchardet==3.0.4\ndj-database-url\ndjango-storages\ndjango==1"
  },
  {
    "path": "src/runtime.txt",
    "chars": 12,
    "preview": "python-3.6.2"
  },
  {
    "path": "src/search/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/search/admin.py",
    "chars": 63,
    "preview": "from django.contrib import admin\n\n# Register your models here.\n"
  },
  {
    "path": "src/search/apps.py",
    "chars": 87,
    "preview": "from django.apps import AppConfig\n\n\nclass SearchConfig(AppConfig):\n    name = 'search'\n"
  },
  {
    "path": "src/search/migrations/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/search/models.py",
    "chars": 57,
    "preview": "from django.db import models\n\n# Create your models here.\n"
  },
  {
    "path": "src/search/templates/search/snippets/search-form.html",
    "chars": 386,
    "preview": "<form method='GET' action='{% url \"search:query\" %}' class=\"form my-2 my-lg-0 search-form\">\n  <div class='input-group'>\n"
  },
  {
    "path": "src/search/templates/search/view.html",
    "chars": 1009,
    "preview": "{% extends \"base.html\" %}\n\n{% block content %}\n <div class='row  mb-3'>\n            {% if query %}\n            <div clas"
  },
  {
    "path": "src/search/tests.py",
    "chars": 60,
    "preview": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "src/search/urls.py",
    "chars": 170,
    "preview": "from django.conf.urls import url\n\nfrom .views import (\n        SearchProductView\n        )\n\nurlpatterns = [\n    url(r'^$"
  },
  {
    "path": "src/search/views.py",
    "chars": 872,
    "preview": "from django.shortcuts import render\nfrom django.views.generic import ListView\nfrom products.models import Product\n\nclass"
  },
  {
    "path": "src/static_my_proj/css/main.css",
    "chars": 25,
    "preview": "body {\n    color: #ccc;\n}"
  },
  {
    "path": "src/static_my_proj/css/stripe-custom-style.css",
    "chars": 578,
    "preview": "/**\n * The CSS shown here will not be introduced in the Quickstart guide, but shows\n * how you can use CSS to style your"
  },
  {
    "path": "src/static_my_proj/js/csrf.ajax.js",
    "chars": 1118,
    "preview": "$(document).ready(function(){\n    // using jQuery\n    function getCookie(name) {\n        var cookieValue = null;\n       "
  },
  {
    "path": "src/static_my_proj/js/ecommerce.js",
    "chars": 7053,
    "preview": "$(document).ready(function(){\n    // Contact Form Handler\n\n    var contactForm = $(\".contact-form\")\n    var contactFormM"
  },
  {
    "path": "src/static_my_proj/js/ecommerce.main.js",
    "chars": 6298,
    "preview": "$(document).ready(function(){\n\n\nvar stripeFormModule = $(\".stripe-payment-form\")\nvar stripeModuleToken = stripeFormModul"
  },
  {
    "path": "src/static_my_proj/js/ecommerce.sales.js",
    "chars": 1697,
    "preview": "\n$(document).ready(function(){\n    function renderChart(id, data, labels){\n        // var ctx = document.getElementById("
  },
  {
    "path": "src/tags/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/tags/admin.py",
    "chars": 83,
    "preview": "from django.contrib import admin\n\nfrom .models import Tag\n\nadmin.site.register(Tag)"
  },
  {
    "path": "src/tags/apps.py",
    "chars": 83,
    "preview": "from django.apps import AppConfig\n\n\nclass TagsConfig(AppConfig):\n    name = 'tags'\n"
  },
  {
    "path": "src/tags/migrations/0001_initial.py",
    "chars": 867,
    "preview": "# -*- coding: utf-8 -*-\n# Generated by Django 1.11.4 on 2017-09-21 00:00\nfrom __future__ import unicode_literals\n\nfrom d"
  },
  {
    "path": "src/tags/migrations/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/tags/models.py",
    "chars": 740,
    "preview": "from django.db import models\nfrom django.db.models.signals import pre_save, post_save\nfrom django.urls import reverse\n\nf"
  },
  {
    "path": "src/tags/shell_commands.py",
    "chars": 1437,
    "preview": "'''\n# Shell session 1\n# python manage.py shell\n'''\n\nfrom tags.models import Tag\n\nqs = Tag.objects.all()\nprint(qs)\nblack "
  },
  {
    "path": "src/tags/tests.py",
    "chars": 60,
    "preview": "from django.test import TestCase\n\n# Create your tests here.\n"
  },
  {
    "path": "src/tags/views.py",
    "chars": 63,
    "preview": "from django.shortcuts import render\n\n# Create your views here.\n"
  },
  {
    "path": "src/templates/400.html",
    "chars": 185,
    "preview": "{% extends \"base.html\" %}\n\n\n{% block content %}\n<div class='row'>\n<div class='col text-center'>\n\n    <h1 class='my-5'>Ba"
  },
  {
    "path": "src/templates/403.html",
    "chars": 196,
    "preview": "{% extends \"base.html\" %}\n\n\n{% block content %}\n<div class='row'>\n<div class='col text-center'>\n\n    \n    <h1 class='my-"
  },
  {
    "path": "src/templates/404.html",
    "chars": 188,
    "preview": "{% extends \"base.html\" %}\n\n\n{% block content %}\n<div class='row'>\n<div class='col text-center'>\n\n    <h1 class='my-5'>Pa"
  },
  {
    "path": "src/templates/500.html",
    "chars": 260,
    "preview": "{% extends \"base.html\" %}\n\n\n{% block content %}\n<div class='row'>\n<div class='col text-center'>\n\n    <h1 class='my-5'>Oo"
  }
]

// ... and 67 more files (download for full content)

About this extraction

This page contains the full source code of the codingforentrepreneurs/ecommerce GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 267 files (841.2 KB), approximately 245.0k tokens, and a symbol index with 490 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!