diff --git a/brewman/models/__init__.py b/brewman/models/__init__.py index 9f5cd16f..279eb45e 100644 --- a/brewman/models/__init__.py +++ b/brewman/models/__init__.py @@ -28,7 +28,7 @@ def fixtures(engine): from brewman.models.messaging import Tag, Thread, Subscriber, thread_tag, Post from brewman.models.voucher import Attendance, Batch, Fingerprint, Inventory, Journal, Product, SalaryDeduction, Voucher, VoucherType from brewman.models.master import Product, AttendanceType, CostCenter, Employee, Ledger, LedgerBase, LedgerType, ProductGroup, MenuItem, Recipe, RecipeItem - from brewman.models.auth import Client, Group, Role, User, role_group, user_group + from brewman.models.auth import Client, Group, Role, User, role_group, user_group, LoginHistory Base.metadata.create_all(engine) diff --git a/brewman/models/auth.py b/brewman/models/auth.py index 96f76410..f05bf660 100644 --- a/brewman/models/auth.py +++ b/brewman/models/auth.py @@ -2,9 +2,10 @@ import random import string import uuid from hashlib import md5 +from datetime import datetime from sqlalchemy.schema import ForeignKey, Table -from sqlalchemy import Column, Boolean, Unicode, Integer +from sqlalchemy import Column, Boolean, Unicode, Integer, DateTime, UniqueConstraint from sqlalchemy.orm import synonym, relationship from brewman.models.guidtype import GUID @@ -19,17 +20,22 @@ def encrypt(val): class Client(Base): __tablename__ = 'auth_clients' - id = Column('ClientID', GUID(), primary_key=True, default=uuid.uuid4) - code = Column('Code', Integer, unique=True, nullable=False) - name = Column('Name', Unicode(255), unique=True, nullable=False) - enabled = Column('Enabled', Boolean, nullable=False) - otp = Column('OTP', Integer) + id = Column('client_id', GUID(), primary_key=True, default=uuid.uuid4) + code = Column('code', Integer, unique=True, nullable=False) + name = Column('name', Unicode(255), unique=True, nullable=False) + enabled = Column('enabled', Boolean, nullable=False) + otp = Column('otp', Integer) + creation_date = Column('creation_date', DateTime(timezone=True), nullable=False) - def __init__(self, code=None, name=None, enabled=False, otp=None): + login_history = relationship('LoginHistory', backref='client') + + def __init__(self, code=None, name=None, enabled=False, otp=None, creation_date=None, id=None): self.code = code self.name = name self.enabled = enabled self.otp = otp + self.creation_date = datetime.utcnow() if creation_date is None else creation_date + self.id = id @classmethod def by_id(cls, id): @@ -85,6 +91,7 @@ class User(Base): locked_out = Column('LockedOut', Boolean) groups = relationship("Group", secondary=user_group) + login_history = relationship('LoginHistory', backref='user') def _get_password(self): return self._password @@ -146,6 +153,21 @@ class User(Base): return query.order_by(cls.name) +class LoginHistory(Base): + __tablename__ = 'auth_login_history' + __table_args__ = (UniqueConstraint('user_id', 'client_id', 'date'), ) + id = Column('login_history_id', GUID(), primary_key=True, default=uuid.uuid4) + user_id = Column('user_id', GUID(), ForeignKey('auth_users.UserID'), nullable=False) + client_id = Column('client_id', GUID(), ForeignKey('auth_clients.client_id'), nullable=False) + date = Column('date', DateTime(timezone=True), nullable=False) + + def __init__(self, user_id=None, client_id=None, date=None, id=None): + self.user_id = user_id + self.client_id = client_id + self.date = datetime.utcnow() if date is None else date + self.id = id + + class Group(Base): __tablename__ = 'auth_groups' diff --git a/brewman/models/voucher.py b/brewman/models/voucher.py index 07f6252b..9207bf11 100644 --- a/brewman/models/voucher.py +++ b/brewman/models/voucher.py @@ -2,8 +2,9 @@ from datetime import datetime import uuid from sqlalchemy.dialects.postgresql import BYTEA +from sqlalchemy.ext.declarative import declared_attr from sqlalchemy.ext.hybrid import hybrid_property -from sqlalchemy import Column, Integer, Boolean, Unicode, DateTime, Numeric, ForeignKey, UniqueConstraint +from sqlalchemy import Column, Integer, Boolean, Unicode, DateTime, Numeric, ForeignKey, UniqueConstraint, Index from sqlalchemy.orm import relationship, synonym, backref from brewman.models.guidtype import GUID @@ -53,7 +54,7 @@ class Voucher(Base): __tablename__ = 'vouchers' id = Column('VoucherID', GUID(), primary_key=True, default=uuid.uuid4) - date = Column('Date', DateTime, nullable=False) + date = Column('Date', DateTime, nullable=False, index=True) reconcile_date = Column('ReconcileDate', DateTime, nullable=False) is_reconciled = Column('IsReconciled', Boolean, nullable=False) narration = Column('Narration', Unicode(1000), nullable=False) @@ -72,6 +73,8 @@ class Voucher(Base): salary_deductions = relationship('SalaryDeduction', backref='voucher', cascade="delete, delete-orphan", cascade_backrefs=False) + + def _get_type(self): return self._type # for item in VoucherType.list(): @@ -123,7 +126,7 @@ class Journal(Base): id = Column('JournalID', GUID(), primary_key=True, default=uuid.uuid4) debit = Column('Debit', Integer) amount = Column('Amount', Numeric) - voucher_id = Column('VoucherID', GUID(), ForeignKey('vouchers.VoucherID'), nullable=False) + voucher_id = Column('VoucherID', GUID(), ForeignKey('vouchers.VoucherID'), nullable=False, index=True) ledger_id = Column('LedgerID', GUID(), ForeignKey('ledgers.LedgerID'), nullable=False) cost_center_id = Column('CostCenterID', GUID(), ForeignKey('cost_centers.CostCenterID'), nullable=False) @@ -190,7 +193,7 @@ class Inventory(Base): __tablename__ = 'inventories' __table_args__ = (UniqueConstraint('VoucherID', 'BatchID'), ) id = Column('InventoryID', GUID(), primary_key=True, default=uuid.uuid4) - voucher_id = Column('VoucherID', GUID(), ForeignKey('vouchers.VoucherID'), nullable=False) + voucher_id = Column('VoucherID', GUID(), ForeignKey('vouchers.VoucherID'), nullable=False, index=True) product_id = Column('ProductID', GUID(), ForeignKey('products.ProductID'), nullable=False) batch_id = Column('BatchID', GUID(), ForeignKey('batches.BatchID'), nullable=False) quantity = Column('Quantity', Numeric) diff --git a/brewman/static/partial/client-list.html b/brewman/static/partial/client-list.html index 1fa72002..cb65faca 100644 --- a/brewman/static/partial/client-list.html +++ b/brewman/static/partial/client-list.html @@ -6,6 +6,7 @@