eventcally/models.py
Daniel Grams 47ab03ca9a Images
- Bilder bei Update: Anzeigen und entfernen
- Images mit Copyright-Text
2020-10-05 08:43:23 +02:00

395 lines
15 KiB
Python

from app import db
from sqlalchemy.ext.declarative import declared_attr
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import relationship, backref, deferred
from sqlalchemy.schema import CheckConstraint
from sqlalchemy.types import TypeDecorator
from sqlalchemy.event import listens_for
from sqlalchemy import UniqueConstraint, Boolean, DateTime, Column, Integer, String, ForeignKey, Unicode, UnicodeText, Numeric, LargeBinary
from flask_security import UserMixin, RoleMixin
from flask_dance.consumer.storage.sqla import OAuthConsumerMixin
from enum import IntEnum
import datetime
from db import IntegerEnum
from geoalchemy2 import Geometry
from sqlalchemy import and_
### Base
class TrackableMixin(object):
created_at = Column(DateTime, default=datetime.datetime.utcnow)
@declared_attr
def created_by_id(cls):
return Column('created_by_id', ForeignKey('user.id'))
@declared_attr
def created_by(cls):
return relationship("User")
### Multi purpose
class Image(db.Model, TrackableMixin):
__tablename__ = 'image'
id = Column(Integer(), primary_key=True)
data = deferred(db.Column(db.LargeBinary))
encoding_format = Column(String(80))
copyright_text = Column(Unicode(255))
def is_empty(self):
return not self.data
### User
class RolesUsers(db.Model):
__tablename__ = 'roles_users'
id = Column(Integer(), primary_key=True)
user_id = Column('user_id', Integer(), ForeignKey('user.id'))
role_id = Column('role_id', Integer(), ForeignKey('role.id'))
class Role(db.Model, RoleMixin):
__tablename__ = 'role'
id = Column(Integer(), primary_key=True)
name = Column(String(80), unique=True)
title = Column(Unicode(255))
description = Column(String(255))
permissions = Column(UnicodeText())
class User(db.Model, UserMixin):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
email = Column(String(255), unique=True)
username = Column(String(255))
password = Column(String(255))
last_login_at = Column(DateTime())
current_login_at = Column(DateTime())
last_login_ip = Column(String(100))
current_login_ip = Column(String(100))
login_count = Column(Integer)
active = Column(Boolean())
fs_uniquifier = Column(String(255))
confirmed_at = Column(DateTime())
roles = relationship('Role', secondary='roles_users',
backref=backref('users', lazy='dynamic'))
class OAuth(OAuthConsumerMixin, db.Model):
provider_user_id = Column(String(256), unique=True, nullable=False)
user_id = Column(Integer(), ForeignKey('user.id'), nullable=False)
user = db.relationship('User')
### Admin Unit
class AdminUnitMemberRolesMembers(db.Model):
__tablename__ = 'adminunitmemberroles_members'
id = Column(Integer(), primary_key=True)
member_id = Column('member_id', Integer(), ForeignKey('adminunitmember.id'))
role_id = Column('role_id', Integer(), ForeignKey('adminunitmemberrole.id'))
class AdminUnitMemberRole(db.Model, RoleMixin):
__tablename__ = 'adminunitmemberrole'
id = Column(Integer(), primary_key=True)
name = Column(String(80), unique=True)
title = Column(Unicode(255))
description = Column(String(255))
permissions = Column(UnicodeText())
class AdminUnitMember(db.Model):
__tablename__ = 'adminunitmember'
id = Column(Integer(), primary_key=True)
admin_unit_id = db.Column(db.Integer, db.ForeignKey('adminunit.id'), nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
user = db.relationship('User', backref=db.backref('adminunitmembers', lazy=True))
roles = relationship('AdminUnitMemberRole', secondary='adminunitmemberroles_members',
order_by="AdminUnitMemberRole.id",
backref=backref('members', lazy='dynamic'))
class AdminUnitMemberInvitation(db.Model):
__tablename__ = 'adminunitmemberinvitation'
__table_args__ = (
UniqueConstraint('email', 'admin_unit_id'),
)
id = Column(Integer(), primary_key=True)
admin_unit_id = db.Column(db.Integer, db.ForeignKey('adminunit.id'), nullable=False)
email = Column(String(255))
roles = Column(UnicodeText())
class AdminUnit(db.Model, TrackableMixin):
__tablename__ = 'adminunit'
id = Column(Integer(), primary_key=True)
name = Column(Unicode(255), unique=True)
short_name = Column(Unicode(100), unique=True)
members = relationship('AdminUnitMember', backref=backref('adminunit', lazy=True))
invitations = relationship('AdminUnitMemberInvitation', backref=backref('adminunit', lazy=True))
event_organizers = relationship('EventOrganizer', backref=backref('adminunit', lazy=True))
event_places = relationship('EventPlace', backref=backref('adminunit', lazy=True))
location_id = db.Column(db.Integer, db.ForeignKey('location.id'))
location = db.relationship('Location')
logo_id = db.Column(db.Integer, db.ForeignKey('image.id'))
logo = db.relationship('Image', uselist=False)
url = Column(String(255))
email = Column(Unicode(255))
phone = Column(Unicode(255))
fax = Column(Unicode(255))
@listens_for(AdminUnit, 'before_insert')
@listens_for(AdminUnit, 'before_update')
def purge_admin_unit(mapper, connect, self):
if self.logo and self.logo.is_empty():
self.logo_id = None
# Universal Types
class Location(db.Model, TrackableMixin):
__tablename__ = 'location'
id = Column(Integer(), primary_key=True)
street = Column(Unicode(255))
postalCode = Column(Unicode(255))
city = Column(Unicode(255))
state = Column(Unicode(255))
country = Column(Unicode(255))
latitude = Column(Numeric(18,16))
longitude = Column(Numeric(19,16))
coordinate = Column(Geometry(geometry_type="POINT"))
def is_empty(self):
return (not self.street
and not self.postalCode
and not self.city
and not self.state
and not self.country
and not self.latitude
and not self.longitude)
def update_coordinate(self):
if self.latitude and self.longitude:
point = 'POINT({} {})'.format(self.longitude, self.latitude)
self.coordinate = point
else:
self.coordinate = None
@classmethod
def update_coordinates(cls):
locations = Location.query.filter(and_(Location.latitude != None, Location.latitude != 0, Location.coordinate == None)).all()
for location in locations:
location.update_coordinate()
db.session.commit()
@listens_for(Location, 'before_insert')
@listens_for(Location, 'before_update')
def update_location_coordinate(mapper, connect, self):
self.update_coordinate()
# Events
class EventPlace(db.Model, TrackableMixin):
__tablename__ = 'eventplace'
__table_args__ = (UniqueConstraint('name', 'organizer_id', 'admin_unit_id'),)
id = Column(Integer(), primary_key=True)
name = Column(Unicode(255), nullable=False)
location_id = db.Column(db.Integer, db.ForeignKey('location.id'))
location = db.relationship('Location', uselist=False)
photo_id = db.Column(db.Integer, db.ForeignKey('image.id'))
photo = db.relationship('Image', uselist=False)
url = Column(String(255))
description = Column(UnicodeText())
public = Column(Boolean())
admin_unit_id = db.Column(db.Integer, db.ForeignKey('adminunit.id'), nullable=True)
organizer_id = db.Column(db.Integer, db.ForeignKey('eventorganizer.id'), nullable=True)
def is_empty(self):
return (not self.name)
@listens_for(EventPlace, 'before_insert')
@listens_for(EventPlace, 'before_update')
def purge_event_place(mapper, connect, self):
if self.location and self.location.is_empty():
self.location_id = None
if self.photo and self.photo.is_empty():
self.photo_id = None
class EventCategory(db.Model):
__tablename__ = 'eventcategory'
id = Column(Integer(), primary_key=True)
name = Column(Unicode(255), nullable=False, unique=True)
class EventTargetGroupOrigin(IntEnum):
both = 1
tourist = 2
resident = 3
class EventAttendanceMode(IntEnum):
offline = 1
online = 2
mixed = 3
class EventStatus(IntEnum):
scheduled = 1
cancelled = 2
movedOnline = 3
postponed = 4
rescheduled = 5
class EventReviewStatus(IntEnum):
inbox = 1
verified = 2
rejected = 3
class EventRejectionReason(IntEnum):
duplicate = 1
untrustworthy = 2
illegal = 3
class EventReferenceRequestReviewStatus(IntEnum):
inbox = 1
verified = 2
rejected = 3
class EventReferenceRequestRejectionReason(IntEnum):
duplicate = 1
untrustworthy = 2
illegal = 3
irrelevant = 4
class EventOrganizer(db.Model, TrackableMixin):
__tablename__ = 'eventorganizer'
__table_args__ = (UniqueConstraint('name', 'admin_unit_id'),)
id = Column(Integer(), primary_key=True)
name = Column(Unicode(255), nullable=False)
url = Column(String(255))
email = Column(Unicode(255))
phone = Column(Unicode(255))
fax = Column(Unicode(255))
location_id = db.Column(db.Integer, db.ForeignKey('location.id'))
location = db.relationship('Location')
logo_id = db.Column(db.Integer, db.ForeignKey('image.id'))
logo = db.relationship('Image', uselist=False)
admin_unit_id = db.Column(db.Integer, db.ForeignKey('adminunit.id'), nullable=True)
event_places = relationship('EventPlace', backref=backref('organizer', lazy=True))
def is_empty(self):
return not self.name
@listens_for(EventOrganizer, 'before_insert')
@listens_for(EventOrganizer, 'before_update')
def purge_event_organizer(mapper, connect, self):
if self.logo and self.logo.is_empty():
self.logo_id = None
class EventContact(db.Model, TrackableMixin):
__tablename__ = 'eventcontact'
id = Column(Integer(), primary_key=True)
name = Column(Unicode(255), nullable=False)
email = Column(Unicode(255))
phone = Column(Unicode(255))
def is_empty(self):
return not self.name
class EventReference(db.Model, TrackableMixin):
__tablename__ = 'eventreference'
id = Column(Integer(), primary_key=True)
event_id = db.Column(db.Integer, db.ForeignKey('event.id'), nullable=False)
admin_unit_id = db.Column(db.Integer, db.ForeignKey('adminunit.id'), nullable=False)
admin_unit = db.relationship('AdminUnit', backref=db.backref('references', lazy=True))
rating = Column(Integer())
class EventReferenceRequest(db.Model, TrackableMixin):
__tablename__ = 'eventreferencerequest'
id = Column(Integer(), primary_key=True)
event_id = db.Column(db.Integer, db.ForeignKey('event.id'), nullable=False)
admin_unit_id = db.Column(db.Integer, db.ForeignKey('adminunit.id'), nullable=False)
admin_unit = db.relationship('AdminUnit', backref=db.backref('reference_requests', lazy=True))
review_status = Column(IntegerEnum(EventReferenceRequestReviewStatus))
rejection_reason = Column(IntegerEnum(EventReferenceRequestRejectionReason))
@hybrid_property
def verified(self):
return self.review_status == EventReferenceRequestReviewStatus.verified
class Event(db.Model, TrackableMixin):
__tablename__ = 'event'
id = Column(Integer(), primary_key=True)
admin_unit_id = db.Column(db.Integer, db.ForeignKey('adminunit.id'), nullable=False)
admin_unit = db.relationship('AdminUnit', backref=db.backref('events', lazy=True))
organizer_id = db.Column(db.Integer, db.ForeignKey('eventorganizer.id'), nullable=True)
organizer = db.relationship('EventOrganizer', uselist=False)
event_place_id = db.Column(db.Integer, db.ForeignKey('eventplace.id'), nullable=True)
event_place = db.relationship('EventPlace', uselist=False)
name = Column(Unicode(255), nullable=False)
description = Column(UnicodeText(), nullable=False)
external_link = Column(String(255))
ticket_link = Column(String(255))
photo_id = db.Column(db.Integer, db.ForeignKey('image.id'))
photo = db.relationship('Image', uselist=False)
category_id = db.Column(db.Integer, db.ForeignKey('eventcategory.id'), nullable=False)
category = relationship('EventCategory', uselist=False)
tags = Column(UnicodeText())
kid_friendly = Column(Boolean())
accessible_for_free = Column(Boolean())
age_from = Column(Integer())
age_to = Column(Integer())
target_group_origin = Column(IntegerEnum(EventTargetGroupOrigin))
attendance_mode = Column(IntegerEnum(EventAttendanceMode))
status = Column(IntegerEnum(EventStatus))
previous_start_date = db.Column(db.DateTime(timezone=True), nullable=True)
review_status = Column(IntegerEnum(EventReviewStatus))
rejection_resaon = Column(IntegerEnum(EventRejectionReason))
rating = Column(Integer())
@hybrid_property
def verified(self):
return self.review_status == EventReviewStatus.verified
# suggestion
contact_id = db.Column(db.Integer, db.ForeignKey('eventcontact.id'), nullable=True)
contact = db.relationship('EventContact', uselist=False)
recurrence_rule = Column(UnicodeText())
start = db.Column(db.DateTime(timezone=True), nullable=True)
end = db.Column(db.DateTime(timezone=True), nullable=True)
dates = relationship('EventDate', backref=backref('event', lazy=False), cascade="all, delete-orphan")
references = relationship('EventReference', backref=backref('event', lazy=False), cascade="all, delete-orphan")
reference_requests = relationship('EventReferenceRequest', backref=backref('event', lazy=False), cascade="all, delete-orphan")
@listens_for(Event, 'before_insert')
@listens_for(Event, 'before_update')
def purge_event(mapper, connect, self):
if self.organizer and self.organizer.is_empty():
self.organizer_id = None
if self.event_place and self.event_place.is_empty():
self.event_place_id = None
if self.contact and self.contact.is_empty():
self.contact_id = None
if self.photo and self.photo.is_empty():
self.photo_id = None
class EventDate(db.Model):
__tablename__ = 'eventdate'
id = Column(Integer(), primary_key=True)
event_id = db.Column(db.Integer, db.ForeignKey('event.id'), nullable=False)
start = db.Column(db.DateTime(timezone=True), nullable=False)
end = db.Column(db.DateTime(timezone=True), nullable=True)
class Analytics(db.Model):
__tablename__ = 'analytics'
id = Column(Integer(), primary_key=True)
key = Column(Unicode(255))
value1 = Column(Unicode(255))
value2 = Column(Unicode(255))
created_at = Column(DateTime, default=datetime.datetime.utcnow)
# Deprecated begin
class FeaturedEventReviewStatus(IntEnum):
inbox = 1
verified = 2
rejected = 3
class FeaturedEventRejectionReason(IntEnum):
duplicate = 1
untrustworthy = 2
illegal = 3
irrelevant = 4
# Deprecated end