covid-formity/formity/models.py

154 lines
5.6 KiB
Python

from datetime import datetime
import enum
import hashlib
import os
from jinja2 import Markup
from formity.extensions import db
from sqlalchemy import event
from sqlalchemy.ext.hybrid import hybrid_property
from formity.utils import get_diff
class Status(enum.Enum):
new = 1
confirmed = 2
allocated = 3
fulfilled = 4
rejected = 5
spam = 6
delegated = 7
intransit = 8
shippingpending = 9
pickuppending = 10
class PostalCode(db.Model):
postalcode = db.Column(db.String, primary_key=True)
address = db.Column(db.String, nullable=False)
city = db.Column(db.String, nullable=False)
voivodeship = db.Column(db.String, nullable=False)
county = db.Column(db.String, nullable=False)
class FaceshieldRequest(db.Model):
id = db.Column(db.Integer, primary_key=True)
entity_info = db.Column(db.String)
full_name = db.Column(db.String)
phone_number = db.Column(db.String)
email = db.Column(db.String)
extra = db.Column(db.String)
faceshield_front_required = db.Column(db.Integer, default=0, server_default='0')
faceshield_model = db.Column(db.String)
faceshield_full_required = db.Column(db.Integer, default=0, server_default='0')
created = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
updated = db.Column(db.DateTime, default=datetime.utcnow, nullable=False,
onupdate=datetime.utcnow)
ua = db.Column(db.String)
ip = db.Column(db.String)
status = db.Column(db.Enum(Status), default=Status.new, server_default='new', nullable=False)
remarks = db.Column(db.String)
faceshield_front_delivered = db.Column(db.Integer, default=0, server_default='0')
faceshield_full_delivered = db.Column(db.Integer, default=0, server_default='0')
adapter_3m_dar_required = db.Column(db.Integer, default=0, server_default='0')
adapter_easybreath_dar_required = db.Column(db.Integer, default=0, server_default='0')
adapter_rd40_dar_required = db.Column(db.Integer, default=0, server_default='0')
adapter_secura_dar_required = db.Column(db.Integer, default=0, server_default='0')
adapter_3m_dar_delivered = db.Column(db.Integer, default=0, server_default='0')
adapter_easybreath_dar_delivered = db.Column(db.Integer, default=0, server_default='0')
adapter_rd40_dar_delivered = db.Column(db.Integer, default=0, server_default='0')
adapter_secura_dar_delivered = db.Column(db.Integer, default=0, server_default='0')
shipping_name = db.Column(db.String)
shipping_street = db.Column(db.String)
shipping_postalcode = db.Column(db.String)
shipping_city = db.Column(db.String)
shipping_latitude = db.Column(db.Float)
shipping_longitude = db.Column(db.Float)
shipping_provider = db.Column(db.String)
shipping_id = db.Column(db.String)
postalcode_info = db.relationship(PostalCode, primaryjoin='remote(PostalCode.postalcode) == foreign(FaceshieldRequest.shipping_postalcode)')
parent_id = db.Column(db.Integer, db.ForeignKey(id))
parent_shipment = db.relationship('FaceshieldRequest', remote_side=id, backref='children')
handling_orga = db.Column(db.String, default='hswaw', server_default='hswaw', nullable=False)
def __str__(self):
return Markup('<a href="/admin/request_unfiltered/edit/?id={}">#{} {}</a> ({})').format(self.id, self.id, self.entity_info, self.status.name)
@property
def label_count(self):
if self.faceshield_full_delivered % 150 == 0 and self.faceshield_full_delivered // 150 > 1:
return self.faceshield_full_delivered // 150
return 1
def changelog_default_user_id():
from flask_login import current_user
return current_user.get_id() if current_user and current_user.get_id() else 'nobody'
class RequestChange(db.Model):
id = db.Column(db.Integer, primary_key=True)
request_id = db.Column(db.Integer, db.ForeignKey(FaceshieldRequest.id))
request = db.relationship(FaceshieldRequest, backref='changelog')
user_id = db.Column(db.String, nullable=False, default=changelog_default_user_id)
state_before = db.Column(db.JSON)
state_after = db.Column(db.JSON)
remarks = db.Column(db.String)
created = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
class ExternalUser(db.Model):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String, nullable=False)
_password = db.Column('password', db.String, nullable=False)
remarks = db.Column(db.String)
def _hash(self, salt, password):
return hashlib.pbkdf2_hmac('sha256', password.encode(), salt.encode(), 213700).hex()
@hybrid_property
def password(self):
return self._password
@password.setter
def password(self, new_pass):
# hack: do not double hash
if self._password == new_pass:
return
salt = hashlib.sha256(os.urandom(16)).hexdigest()
self._password = salt + ':' + self._hash(salt, new_pass)
def check_password(self, password):
salt, h = self.password.split(':')
return self._hash(salt, password) == h
@event.listens_for(FaceshieldRequest, 'after_update')
def on_request_change(mapper, connection, target):
try:
before, after = get_diff(target)
except Exception as exc:
# xD
before, after = {'diff': 'failed'}, {'diff': 'failed'}
if before or after:
@event.listens_for(db.session, "after_flush", once=True)
def receive_after_flush(session, context):
db.session.add(RequestChange(
request_id=target.id,
state_before=before,
state_after=after,
))