diff --git a/bootstrap/webapp/templates/layout.html b/bootstrap/webapp/templates/layout.html
index dbf0faf..d253c59 100644
--- a/bootstrap/webapp/templates/layout.html
+++ b/bootstrap/webapp/templates/layout.html
@@ -114,6 +114,8 @@
.pull-right {
float: right;
+ right: 50px;
+ position: relative;
}
pre {
diff --git a/bootstrap/webapp/templates/navigation.html b/bootstrap/webapp/templates/navigation.html
index 37e28b8..0415a01 100644
--- a/bootstrap/webapp/templates/navigation.html
+++ b/bootstrap/webapp/templates/navigation.html
@@ -1 +1,9 @@
-Home |
\ No newline at end of file
+Home |
+
\ No newline at end of file
diff --git a/oshipka/persistance/__init__.py b/oshipka/persistance/__init__.py
index 4f44ad6..4b9e3e4 100644
--- a/oshipka/persistance/__init__.py
+++ b/oshipka/persistance/__init__.py
@@ -1,12 +1,94 @@
+import datetime
import os
+import re
+from json import JSONEncoder
+from uuid import uuid4
from flask_sqlalchemy import SQLAlchemy
+from flask_security import Security, SQLAlchemyUserDatastore
+from sqlalchemy.ext.declarative import declared_attr
+from flask_security import RoleMixin, UserMixin
from config import SQLALCHEMY_DATABASE_URI, MAKEDIRS, DATABASE_FILE
db = SQLAlchemy()
+class Ownable(object):
+ @declared_attr
+ def user_id(self):
+ return db.Column(db.Integer, db.ForeignKey('user.id'))
+
+ @declared_attr
+ def user(self):
+ return db.relationship("User")
+
+
+roles_users = db.Table('roles_users',
+ db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
+ db.Column('role_id', db.Integer(), db.ForeignKey('role.id')))
+
+
+class ModelJsonEncoder(JSONEncoder):
+ def default(self, o):
+ if isinstance(o, datetime.datetime):
+ return str(o)
+ return o.id
+
+
+def camel_case_to_snake_case(name):
+ """
+ Convertes a CamelCase name to snake_case
+ :param name: the name to be converted
+ :return:
+ """
+ s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
+ return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
+
+
+class ModelController(ModelJsonEncoder):
+ """
+ This interface is the parent of all models in our database.
+ """
+
+ @declared_attr
+ def __tablename__(self):
+ return camel_case_to_snake_case(self.__name__) # pylint: disable=E1101
+
+ _sa_declared_attr_reg = {'__tablename__': True}
+ __mapper_args__ = {'always_refresh': True}
+
+ id = db.Column(db.Integer, primary_key=True)
+ uuid = db.Column(db.Unicode, default=str(uuid4()))
+
+
+class Role(db.Model, ModelController, RoleMixin):
+ name = db.Column(db.Unicode, unique=True)
+ description = db.Column(db.Unicode)
+
+
+class User(db.Model, ModelController, UserMixin):
+ email = db.Column(db.Unicode, unique=True)
+ password = db.Column(db.Unicode)
+
+ active = db.Column(db.Boolean(), default=True)
+ confirmed_at = db.Column(db.DateTime())
+
+ timezone = db.Column(db.String, default='UTC')
+ tz_offset_seconds = db.Column(db.Integer, default=0)
+ locale = db.Column(db.String(4), default='en')
+
+ name = db.Column(db.Unicode)
+ profile_image_url = db.Column(db.String)
+
+ roles = db.relationship('Role', secondary=roles_users,
+ backref=db.backref('users', lazy='dynamic'))
+
+
+security = Security()
+user_datastore = SQLAlchemyUserDatastore(db, User, Role)
+
+
def init_db(app):
app.config["SQLALCHEMY_DATABASE_URI"] = SQLALCHEMY_DATABASE_URI
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
@@ -16,9 +98,11 @@ def init_db(app):
app.register_blueprint(oshipka_bp)
db.init_app(app)
+ security.init_app(app, user_datastore)
+
for dir in MAKEDIRS:
os.makedirs(dir, exist_ok=True)
if not os.path.exists(DATABASE_FILE):
with app.app_context():
db.create_all()
- return True
+ return True
\ No newline at end of file
diff --git a/oshipka/webapp/__init__.py b/oshipka/webapp/__init__.py
index 1c3de1c..fbc5366 100644
--- a/oshipka/webapp/__init__.py
+++ b/oshipka/webapp/__init__.py
@@ -2,6 +2,7 @@ from flask import Flask, Blueprint
app = Flask(__name__)
app.config["SECRET_KEY"] = "UNSECRET_KEY....478932fjkdsl"
+app.config["SECURITY_PASSWORD_SALT"] = "UNSECRETfdsafsda_KEY....478932fjkdsl"
test_bp = Blueprint('test_bp', __name__,
url_prefix="/test",
diff --git a/requirements.txt b/requirements.txt
index d72d744..dc69db6 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,20 +1,33 @@
Babel==2.8.0
+bcrypt==3.1.7
+blinker==1.4
+cffi==1.14.0
click==7.1.1
filelock==3.0.12
Flask==1.1.1
Flask-Babel==1.0.0
+Flask-BabelEx==0.9.4
+Flask-Login==0.5.0
+Flask-Mail==0.9.1
+Flask-Principal==0.4.0
+Flask-Security==3.0.0
Flask-SQLAlchemy==2.4.1
Flask-Table==0.5.0
+Flask-WTF==0.14.3
importlib-metadata==1.5.2
inflect==4.1.0
itsdangerous==1.1.0
Jinja2==2.11.1
MarkupSafe==1.1.1
+passlib==1.7.2
pathtools==0.1.2
+pycparser==2.20
pytz==2019.3
six==1.14.0
+speaklater==1.3
SQLAlchemy==1.3.15
SQLAlchemy-Utils==0.36.3
watchdog==0.10.2
Werkzeug==1.0.0
+WTForms==2.2.1
zipp==3.1.0