From db9f27741e9dbeab90fb4553776388b66ee7be35 Mon Sep 17 00:00:00 2001 From: androiddrew Date: Tue, 3 Apr 2018 13:35:39 -0400 Subject: [PATCH] initial commit --- .gitignore | 69 +++++++++++++++++++++++++++++++++++ README.md | 0 cookiedb/__init__.py | 1 + cookiedb/models.py | 87 ++++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 6 +++ setup.py | 17 +++++++++ 6 files changed, 180 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 cookiedb/__init__.py create mode 100644 cookiedb/models.py create mode 100644 requirements.txt create mode 100644 setup.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bbbf9b1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,69 @@ +# virtualenv +env + +# Pycharm +.idea + +# ---> Python +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +pypyenv/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.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 + +# Translations +*.mo +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +docs/_build/ + +# Redis +/dump.rdb + +# Project +config.py \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/cookiedb/__init__.py b/cookiedb/__init__.py new file mode 100644 index 0000000..a9c702b --- /dev/null +++ b/cookiedb/__init__.py @@ -0,0 +1 @@ +from cookiedb.models import Base \ No newline at end of file diff --git a/cookiedb/models.py b/cookiedb/models.py new file mode 100644 index 0000000..4bf2e41 --- /dev/null +++ b/cookiedb/models.py @@ -0,0 +1,87 @@ +import bcrypt +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy import Column, Integer, String, ForeignKey, DateTime, Boolean, Numeric +from sqlalchemy.orm import relationship, backref +from sqlalchemy.sql import expression +from sqlalchemy.ext.compiler import compiles +from sqlalchemy.types import DateTime as DateTimeType + +BCRYPT_LOG_ROUNDS = 11 + + +# can be moved to models util? +class utcnow(expression.FunctionElement): + type = DateTimeType() + + +# Can be moved to the models util? +@compiles(utcnow, 'postgresql') +def pg_utcnow(element, compiler, **kw): + return "TIMEZONE('utc', CURRENT_TIMESTAMP)" + + +Base = declarative_base() + + +class DBMixin: + id = Column(Integer, primary_key=True, autoincrement=True) + created_date = Column(DateTime, server_default=utcnow()) + modified_date = Column(DateTime, server_default=utcnow(), onupdate=utcnow()) + + def to_dict(self): + d = self.__dict__.copy() + if '_sa_instance_state' in d: + d.pop('_sa_instance_state') + return d + + +def ReferenceCol(tablename, nullable=False, **kw): + return Column(ForeignKey('{}.id'.format(tablename)), nullable=nullable, **kw) + + +class Cookie(Base, DBMixin): + __tablename__ = 'cookies' + + name = Column(String(50), index=True) + recipe_url = Column(String(255)) + sku = Column(String(55)) + qoh = Column(Integer) + unit_cost = Column(Numeric(12, 2)) + + +class User(DBMixin, Base): + __tablename__ = 'users' + + email = Column(String(255), nullable=False, unique=True) + password = Column(String(255)) + admin = Column(Boolean, nullable=False, default=False) + confirmed = Column(Boolean, nullable=False, default=False) + + def __init__(self, email, password, admin=False): + self.email = email + self.password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt(BCRYPT_LOG_ROUNDS)).decode() + self.admin = admin + + def check_password(self, password): + return bcrypt.checkpw(password.encode('utf-8'), self.password.encode('utf-8')) + + +class Order(DBMixin, Base): + __tablename__ = 'orders' + + user_id = ReferenceCol('users') + shipped = Column(Boolean, default=False) + + user = relationship('User', backref=backref('orders')) + + +class LineItem(DBMixin, Base): + __tablename__ = 'line_items' + + order_id = ReferenceCol('orders') + cookie_id = ReferenceCol('cookies') + quantity = Column(Integer) + extended_cost = Column(Numeric(12, 2)) + + order = relationship('Order', backref=backref('line_items')) + cookie = relationship('Cookie', uselist=False) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..22dc1ab --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +bcrypt==3.1.4 +cffi==1.11.5 +psycopg2==2.7.4 +pycparser==2.18 +six==1.11.0 +SQLAlchemy==1.2.6 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..ea6b8e4 --- /dev/null +++ b/setup.py @@ -0,0 +1,17 @@ +from setuptools import setup, find_packages + +with open('requirements.txt') as f: + requirements = [requirement for requirement in f] + + +setup( + name='cookiedb', + version='0.1.0', + description='A sample domain model to be used for toy applications', + packages=find_packages(), + author='Drew Bednar', + author_email='drew@androiddrew.com', + install_requires=requirements, + license='MIT', +) +