From ba16a512f353e154e1033af2d3b98c6a0215405a Mon Sep 17 00:00:00 2001 From: Alexis Lahouze Date: Mon, 31 Aug 2015 10:55:05 +0200 Subject: [PATCH] Add user model. --- accountant/api/models/users.py | 69 +++++++++++++++++++ .../versions/1232daf66ac_add_user_support.py | 34 +++++++++ 2 files changed, 103 insertions(+) create mode 100644 accountant/api/models/users.py create mode 100644 migrations/versions/1232daf66ac_add_user_support.py diff --git a/accountant/api/models/users.py b/accountant/api/models/users.py new file mode 100644 index 0000000..5235647 --- /dev/null +++ b/accountant/api/models/users.py @@ -0,0 +1,69 @@ +""" + This file is part of Accountant. + + Accountant is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Accountant is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with Accountant. If not, see . +""" +# vim: set tw=80 ts=4 sw=4 sts=4: +from passlib.hash import sha256_crypt +from itsdangerous import (TimedJSONWebSignatureSerializer as Serializer, + BadSignature, SignatureExpired) + +from flask import current_app as app + +from flask.ext.login import UserMixin + +from sqlalchemy import true + +from accountant import db + + +class User(UserMixin, db.Model): + id = db.Column(db.Integer, primary_key=True) + email = db.Column(db.String(200), nullable=False, unique=True, index=True) + password = db.Column(db.String(100), nullable=True) + active = db.Column(db.Boolean, nullable=False, default=True, + server_default=true()) + + @property + def is_active(self): + return self.active + + @classmethod + def query(cls, session): + return session.query(cls) + + @classmethod + def hash_password(cls, password): + return sha256_crypt.encrypt(password) + + def verify_password(self, password): + return sha256_crypt.verify(password, self.password) + + def generate_auth_token(self, expiration=600): + serializer = Serializer(app.config['SECRET_KEY'], expires_in=expiration) + return serializer.dumps({'id': self.id}) + + @classmethod + def verify_auth_token(cls, session, token): + serializer = Serializer(app.config['SECRET_KEY']) + + try: + data = serializer.loads(token) + except SignatureExpired: + return None + except BadSignature: + return None + + user = cls.query(session).get(data['id']) + return user diff --git a/migrations/versions/1232daf66ac_add_user_support.py b/migrations/versions/1232daf66ac_add_user_support.py new file mode 100644 index 0000000..bbc6bbb --- /dev/null +++ b/migrations/versions/1232daf66ac_add_user_support.py @@ -0,0 +1,34 @@ +"""Add user support. + +Revision ID: 1232daf66ac +Revises: 144929e0f5f +Create Date: 2015-08-31 10:24:40.578432 + +""" + +# revision identifiers, used by Alembic. +revision = '1232daf66ac' +down_revision = '144929e0f5f' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + ### commands auto generated by Alembic - please adjust! ### + op.create_table('user', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('email', sa.String(length=200), nullable=False), + sa.Column('password', sa.String(length=100), nullable=True), + sa.Column('active', sa.Boolean(), server_default=sa.text('true'), nullable=False), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_user_email'), 'user', ['email'], unique=True) + ### end Alembic commands ### + + +def downgrade(): + ### commands auto generated by Alembic - please adjust! ### + op.drop_index(op.f('ix_user_email'), table_name='user') + op.drop_table('user') + ### end Alembic commands ###