mirror of
https://github.com/lucaspalomodevelop/eventcally.git
synced 2026-03-13 00:07:22 +00:00
image
This commit is contained in:
parent
38ae395bef
commit
34f07ae562
87
app.py
87
app.py
@ -1,5 +1,6 @@
|
||||
import os
|
||||
from flask import Flask, render_template, request, url_for, redirect, abort, flash
|
||||
from base64 import b64decode
|
||||
from flask import Flask, render_template, request, url_for, redirect, abort, flash, current_app
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from sqlalchemy.orm import joinedload
|
||||
from sqlalchemy.sql import asc, func
|
||||
@ -39,7 +40,7 @@ db = SQLAlchemy(app)
|
||||
|
||||
# Setup Flask-Security
|
||||
# Define models
|
||||
from models import EventSuggestion, EventSuggestionDate, OrgOrAdminUnit, Actor, Place, Location, User, Role, AdminUnit, AdminUnitMember, AdminUnitMemberRole, OrgMember, OrgMemberRole, Organization, AdminUnitOrg, AdminUnitOrgRole, Event, EventDate
|
||||
from models import Image, EventSuggestion, EventSuggestionDate, OrgOrAdminUnit, Actor, Place, Location, User, Role, AdminUnit, AdminUnitMember, AdminUnitMemberRole, OrgMember, OrgMemberRole, Organization, AdminUnitOrg, AdminUnitOrgRole, Event, EventDate
|
||||
user_datastore = SQLAlchemySessionUserDatastore(db.session, User, Role)
|
||||
security = Security(app, user_datastore)
|
||||
|
||||
@ -47,6 +48,10 @@ security = Security(app, user_datastore)
|
||||
def get_locale():
|
||||
return request.accept_languages.best_match(app.config['LANGUAGES'])
|
||||
|
||||
def get_img_resource(res):
|
||||
with current_app.open_resource('static/img/' + res) as f:
|
||||
return f.read()
|
||||
|
||||
# Create a user to test with
|
||||
def upsert_user(email, password="password"):
|
||||
result = user_datastore.find_user(email=email)
|
||||
@ -140,12 +145,39 @@ def add_role_to_org_member(org_member, role):
|
||||
if OrgMemberRole.query.with_parent(org_member).filter_by(name = role.name).first() is None:
|
||||
org_member.roles.append(role)
|
||||
|
||||
def upsert_organization(org_name):
|
||||
def upsert_image_with_data(image, data):
|
||||
if image is None:
|
||||
image = Image()
|
||||
|
||||
image.data = b64decode(data)
|
||||
image.encoding_format = "image/jpeg"
|
||||
|
||||
return image
|
||||
|
||||
def upsert_image_with_res(image, res):
|
||||
if image is None:
|
||||
image = Image()
|
||||
|
||||
image.data = get_img_resource(res)
|
||||
image.encoding_format = "image/jpeg"
|
||||
|
||||
return image
|
||||
|
||||
def upsert_organization(org_name, street = None, postalCode = None, city = None, latitude = 0, longitude = 0, legal_name = None, url=None, logo_res=None):
|
||||
result = Organization.query.filter_by(name = org_name).first()
|
||||
if result is None:
|
||||
result = Organization(name = org_name)
|
||||
db.session.add(result)
|
||||
|
||||
result.legal_name = legal_name
|
||||
result.url = url
|
||||
|
||||
if city is not None:
|
||||
result.location = upsert_location(street, postalCode, city, latitude, longitude)
|
||||
|
||||
if logo_res is not None:
|
||||
result.logo = upsert_image_with_res(result.logo, logo_res)
|
||||
|
||||
upsert_org_or_admin_unit_for_organization(result)
|
||||
return result
|
||||
|
||||
@ -184,15 +216,24 @@ def upsert_location(street, postalCode, city, latitude = 0, longitude = 0):
|
||||
|
||||
return result
|
||||
|
||||
def upsert_place(name, street = None, postalCode = None, city = None, latitude = 0, longitude = 0):
|
||||
def upsert_place(name, street = None, postalCode = None, city = None, latitude = 0, longitude = 0, url=None, description=None, photo_res=None):
|
||||
result = Place.query.filter_by(name = name).first()
|
||||
if result is None:
|
||||
result = Place(name = name)
|
||||
db.session.add(result)
|
||||
|
||||
if url:
|
||||
result.url=url
|
||||
|
||||
if description:
|
||||
result.description=description
|
||||
|
||||
if city is not None:
|
||||
result.location = upsert_location(street, postalCode, city, latitude, longitude)
|
||||
|
||||
if photo_res is not None:
|
||||
result.photo = upsert_image_with_res(result.photo, photo_res)
|
||||
|
||||
return result
|
||||
|
||||
def upsert_event_suggestion(event_name, host_name, place_name, start, description, link = None, admin_unit = None):
|
||||
@ -222,7 +263,7 @@ def upsert_event_suggestion(event_name, host_name, place_name, start, descriptio
|
||||
|
||||
return result
|
||||
|
||||
def upsert_event(event_name, host, location_name, start, description, link = None, verified = False, admin_unit = None):
|
||||
def upsert_event(event_name, host, location_name, start, description, link = None, verified = False, admin_unit = None, ticket_link=None, photo_res=None):
|
||||
if admin_unit is None:
|
||||
admin_unit = get_admin_unit('Stadt Goslar')
|
||||
place = upsert_place(location_name)
|
||||
@ -239,11 +280,15 @@ def upsert_event(event_name, host, location_name, start, description, link = Non
|
||||
result.admin_unit = admin_unit
|
||||
result.host = host
|
||||
result.place = place
|
||||
result.ticket_link = ticket_link
|
||||
|
||||
eventDate = EventDate(event_id = result.id, start=start)
|
||||
result.dates = []
|
||||
result.dates.append(eventDate)
|
||||
|
||||
if photo_res is not None:
|
||||
result.photo = upsert_image_with_res(result.photo, photo_res)
|
||||
|
||||
return result
|
||||
|
||||
def get_event_hosts():
|
||||
@ -544,6 +589,7 @@ def create_user():
|
||||
gz = upsert_organization("Goslarsche Zeitung")
|
||||
celtic_inn = upsert_organization("Celtic Inn")
|
||||
kloster_woelteringerode = upsert_organization("Kloster Wöltingerode")
|
||||
miners_rock = upsert_organization("Miner's Rock", "Kuhlenkamp 36", "38640", "Goslar", legal_name="Miner's Rock UG (haftungsbeschränkt)", url="https://www.miners-rock.de/", logo_res="minersrock.jpeg")
|
||||
|
||||
gmg_admin_unit_org = add_organization_to_admin_unit(gmg, goslar)
|
||||
add_role_to_admin_unit_org(gmg_admin_unit_org, admin_unit_org_event_verifier_role)
|
||||
@ -552,6 +598,7 @@ def create_user():
|
||||
add_role_to_admin_unit_org(gz_admin_unit_org, admin_unit_org_event_verifier_role)
|
||||
|
||||
add_organization_to_admin_unit(celtic_inn, goslar)
|
||||
add_organization_to_admin_unit(miners_rock, goslar)
|
||||
add_organization_to_admin_unit(upsert_organization("Aids-Hilfe Goslar"), goslar)
|
||||
add_organization_to_admin_unit(upsert_organization("Akademie St. Jakobushaus"), goslar)
|
||||
add_organization_to_admin_unit(upsert_organization("Aktiv für Hahndorf e. V."), goslar)
|
||||
@ -610,7 +657,6 @@ def create_user():
|
||||
add_organization_to_admin_unit(upsert_organization("Marktkirche Goslar"), goslar)
|
||||
add_organization_to_admin_unit(upsert_organization("Media Markt "), goslar)
|
||||
add_organization_to_admin_unit(upsert_organization("MGV Juventa von 1877 e. V."), goslar)
|
||||
add_organization_to_admin_unit(upsert_organization("Miners' Rock!"), goslar)
|
||||
add_organization_to_admin_unit(upsert_organization("Mönchehaus Museum"), goslar)
|
||||
add_organization_to_admin_unit(upsert_organization("MTV Goslar e. V."), goslar)
|
||||
add_organization_to_admin_unit(upsert_organization("Museumsverein Goslar e. V."), goslar)
|
||||
@ -650,7 +696,8 @@ def create_user():
|
||||
upsert_place("Marktplatz Goslar", 'Markt 6', '38640', 'Goslar', 51.9063601, 10.4249433)
|
||||
upsert_place("Burg Vienenburg", 'Burgweg 2', '38690', 'Goslar', 51.9476558, 10.5617368)
|
||||
upsert_place("Kurhaus Bad Harzburg", 'Kurhausstraße 11', '38667', 'Bad Harzburg', 51.8758165, 10.5593392)
|
||||
upsert_place("Goslarsche Höfe", 'Okerstraße 32', '38640', 'Goslar', 51.911571, 10.4391331)
|
||||
upsert_place("Goslarsche Höfe", 'Okerstraße 32', '38640', 'Goslar', 51.911571, 10.4391331, 'https://www.goslarsche-hoefe.de/', 'Dir Rosserei', photo_res="schlosserei.jpeg")
|
||||
upsert_place("Schlosserei im Rammelsberg", 'Bergtal 19', '38640', 'Goslar', 51.890527, 10.418880, 'http://www.rammelsberg.de/', 'Die "Schlosserei" ist erprobter Veranstaltungsort und bietet Platz für ca. 700 Besucher. Das Ambiente ist technisch gut ausgestattet und flexibel genug, für jeden Künstler individuell wandelbar zu sein. Dabei lebt nicht nur der Veranstaltungsraum, es wirkt der gesamte Komplex des Rammelsberges und macht den Besuch zu einem unvergeßlichen Erlebnis.', photo_res="schlosserei.jpeg")
|
||||
|
||||
# Org or admins
|
||||
goslar_ooa = upsert_org_or_admin_unit_for_admin_unit(goslar)
|
||||
@ -694,6 +741,10 @@ def create_user():
|
||||
jason_celtic_inn_member = add_user_to_organization(jason, celtic_inn)
|
||||
add_role_to_org_member(jason_celtic_inn_member, org_member_event_creator_role)
|
||||
|
||||
grzno = upsert_user("grzno@test.de")
|
||||
grzno_miners_rock_member = add_user_to_organization(grzno, miners_rock)
|
||||
add_role_to_org_member(grzno_miners_rock_member, org_member_event_creator_role)
|
||||
|
||||
# Events
|
||||
berlin = pytz.timezone('Europe/Berlin')
|
||||
upsert_event("Vienenburger Seefest",
|
||||
@ -757,6 +808,15 @@ def create_user():
|
||||
'Zum letzten Mal in dieser Saison gibt es einen Hof-Flohmarkt. Wir bieten zwar nicht den größten, aber vielleicht den gemütlichsten Flohmarkt in der Region. Frei von gewerblichen Anbietern, dafür mit Kaffee, Kuchen, Bier und Bratwurst, alles auf unserem schönen Hofgelände.',
|
||||
'https://www.goslarsche-hoefe.de/veranstaltungen/10/2175252/2020/10/10/herbst-flohmarkt.html')
|
||||
|
||||
upsert_event('"MINER\'S ROCK" Schickt XVI - Lotte',
|
||||
miners_rock.org_or_adminunit,
|
||||
"Schlosserei im Rammelsberg",
|
||||
create_berlin_date(2020, 10, 31, 19, 0),
|
||||
'Auch im Jahr 2020 wagt sich das MINER’S ROCK wieder an eine Doppel-Schicht. LOTTE wird bei uns das Wochenende am Berg abrunden! Nach der bereits ausverkauften Schicht am 30. Oktober mit Subway to Sally, wird Lotte den Samstagabend zu einem Pop-Erlebnis machen.\nAb Anfang Februar ist sie in den Konzerthallen in Deutschland unterwegs und wird ihr neues Album „Glück“ vorstellen. Glück ist der langersehnte Nachfolger von LOTTEs Debütalbum „Querfeldein". Mit Songs wie der ersten Single „Schau mich nicht so an" oder dem Duett mit Max Giesinger „Auf das was da noch kommt“, durchmisst LOTTE dabei die Höhen und Tiefen des menschlichen Glücksstrebens. Und auch wenn jeder der zwölf Songs seine eigene Geschichte erzählt – sie alle eint die Suche nach der ganz persönlichen Bedeutung dieses großen Wortes. Glück ist kein Werk über einen abgeschlossenen Prozess, sondern ein beeindruckend ehrliches und facettenreiches Album über eine menschliche Suche. „Auf das was da noch kommt“ läuft derzeit in den Radiostationen auf und ab und macht einfach Spaß.\n\nWichtig zu wissen:\n\nEinlass: 19:00 Uhr\nBeginn des Musikprogramms: 20:00 Uhr\nTickets gibt es ab sofort im Shop des MINER‘S ROCK unter www.miners-rock.de und in den Geschäftsstellen der Goslarschen Zeitung.',
|
||||
'https://www.miners-rock.de/xvi-lotte',
|
||||
ticket_link='https://www.regiolights.de/tickets/product/schicht-xvi-lotte',
|
||||
photo_res="lotte.jpeg")
|
||||
|
||||
db.session.commit()
|
||||
|
||||
# Views
|
||||
@ -790,7 +850,7 @@ def organizations():
|
||||
|
||||
@app.route('/organization/<int:organization_id>')
|
||||
def organization(organization_id):
|
||||
organization = Organization.query.filter_by(id = organization_id).first()
|
||||
organization = Organization.query.get_or_404(organization_id)
|
||||
current_user_member = OrgMember.query.with_parent(organization).filter_by(user_id = current_user.id).first() if current_user.is_authenticated else None
|
||||
|
||||
ooa = upsert_org_or_admin_unit_for_organization(organization)
|
||||
@ -802,11 +862,22 @@ def organization(organization_id):
|
||||
can_list_members=can_list_org_members(organization),
|
||||
events=events)
|
||||
|
||||
@app.route('/image/<int:id>')
|
||||
def image(id):
|
||||
image = Image.query.get_or_404(id)
|
||||
return app.response_class(image.data, mimetype=image.encoding_format)
|
||||
|
||||
@app.route("/profile")
|
||||
@auth_required()
|
||||
def profile():
|
||||
return render_template('profile.html')
|
||||
|
||||
@app.route("/places")
|
||||
def places():
|
||||
places = Place.query.order_by(asc(func.lower(Place.name))).all()
|
||||
return render_template('place/list.html',
|
||||
places=places)
|
||||
|
||||
@app.route('/place/<int:place_id>')
|
||||
def place(place_id):
|
||||
place = Place.query.filter_by(id = place_id).first()
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
"""empty message
|
||||
|
||||
Revision ID: 93158b40fde6
|
||||
Revision ID: ea09dc1839df
|
||||
Revises:
|
||||
Create Date: 2020-06-21 15:45:24.988479
|
||||
Create Date: 2020-06-23 12:04:01.423454
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
@ -10,7 +10,7 @@ import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '93158b40fde6'
|
||||
revision = 'ea09dc1839df'
|
||||
down_revision = None
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
@ -75,6 +75,15 @@ def upgrade():
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('name')
|
||||
)
|
||||
op.create_table('image',
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('data', sa.LargeBinary(), nullable=True),
|
||||
sa.Column('encoding_format', sa.String(length=80), nullable=True),
|
||||
sa.Column('created_by_id', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['created_by_id'], ['user.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('location',
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
@ -89,15 +98,6 @@ def upgrade():
|
||||
sa.ForeignKeyConstraint(['created_by_id'], ['user.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('organization',
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.Unicode(length=255), nullable=True),
|
||||
sa.Column('created_by_id', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['created_by_id'], ['user.id'], ),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('name')
|
||||
)
|
||||
op.create_table('roles_users',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('user_id', sa.Integer(), nullable=True),
|
||||
@ -106,17 +106,6 @@ def upgrade():
|
||||
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('actor',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('user_id', sa.Integer(), nullable=False),
|
||||
sa.Column('organization_id', sa.Integer(), nullable=True),
|
||||
sa.Column('admin_unit_id', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['admin_unit_id'], ['adminunit.id'], ),
|
||||
sa.ForeignKeyConstraint(['organization_id'], ['organization.id'], ),
|
||||
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('user_id', 'organization_id', 'admin_unit_id')
|
||||
)
|
||||
op.create_table('adminunitmember',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('admin_unit_id', sa.Integer(), nullable=False),
|
||||
@ -125,14 +114,6 @@ def upgrade():
|
||||
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('adminunitorg',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('admin_unit_id', sa.Integer(), nullable=False),
|
||||
sa.Column('organization_id', sa.Integer(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['admin_unit_id'], ['adminunit.id'], ),
|
||||
sa.ForeignKeyConstraint(['organization_id'], ['organization.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('eventsuggestion',
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
@ -152,6 +133,70 @@ def upgrade():
|
||||
sa.ForeignKeyConstraint(['created_by_id'], ['user.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('organization',
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.Unicode(length=255), nullable=True),
|
||||
sa.Column('legal_name', sa.Unicode(length=255), nullable=True),
|
||||
sa.Column('location_id', sa.Integer(), nullable=True),
|
||||
sa.Column('logo_id', sa.Integer(), nullable=True),
|
||||
sa.Column('url', sa.String(length=255), nullable=True),
|
||||
sa.Column('created_by_id', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['created_by_id'], ['user.id'], ),
|
||||
sa.ForeignKeyConstraint(['location_id'], ['location.id'], ),
|
||||
sa.ForeignKeyConstraint(['logo_id'], ['image.id'], ),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('name')
|
||||
)
|
||||
op.create_table('place',
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.Unicode(length=255), nullable=False),
|
||||
sa.Column('location_id', sa.Integer(), nullable=True),
|
||||
sa.Column('photo_id', sa.Integer(), nullable=True),
|
||||
sa.Column('url', sa.String(length=255), nullable=True),
|
||||
sa.Column('description', sa.UnicodeText(), nullable=True),
|
||||
sa.Column('created_by_id', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['created_by_id'], ['user.id'], ),
|
||||
sa.ForeignKeyConstraint(['location_id'], ['location.id'], ),
|
||||
sa.ForeignKeyConstraint(['photo_id'], ['image.id'], ),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('name')
|
||||
)
|
||||
op.create_table('actor',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('user_id', sa.Integer(), nullable=False),
|
||||
sa.Column('organization_id', sa.Integer(), nullable=True),
|
||||
sa.Column('admin_unit_id', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['admin_unit_id'], ['adminunit.id'], ),
|
||||
sa.ForeignKeyConstraint(['organization_id'], ['organization.id'], ),
|
||||
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('user_id', 'organization_id', 'admin_unit_id')
|
||||
)
|
||||
op.create_table('adminunitmemberroles_members',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('member_id', sa.Integer(), nullable=True),
|
||||
sa.Column('role_id', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['member_id'], ['adminunitmember.id'], ),
|
||||
sa.ForeignKeyConstraint(['role_id'], ['adminunitmemberrole.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('adminunitorg',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('admin_unit_id', sa.Integer(), nullable=False),
|
||||
sa.Column('organization_id', sa.Integer(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['admin_unit_id'], ['adminunit.id'], ),
|
||||
sa.ForeignKeyConstraint(['organization_id'], ['organization.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('eventsuggestiondate',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('event_suggestion_id', sa.Integer(), nullable=False),
|
||||
sa.Column('start', sa.DateTime(timezone=True), nullable=False),
|
||||
sa.ForeignKeyConstraint(['event_suggestion_id'], ['eventsuggestion.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('org_or_adminunit',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('organization_id', sa.Integer(), nullable=True),
|
||||
@ -170,25 +215,6 @@ def upgrade():
|
||||
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('place',
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.Unicode(length=255), nullable=False),
|
||||
sa.Column('location_id', sa.Integer(), nullable=True),
|
||||
sa.Column('created_by_id', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['created_by_id'], ['user.id'], ),
|
||||
sa.ForeignKeyConstraint(['location_id'], ['location.id'], ),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('name')
|
||||
)
|
||||
op.create_table('adminunitmemberroles_members',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('member_id', sa.Integer(), nullable=True),
|
||||
sa.Column('role_id', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['member_id'], ['adminunitmember.id'], ),
|
||||
sa.ForeignKeyConstraint(['role_id'], ['adminunitmemberrole.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('adminunitorgroles_organizations',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('admin_unit_org_id', sa.Integer(), nullable=True),
|
||||
@ -208,20 +234,15 @@ def upgrade():
|
||||
sa.Column('external_link', sa.String(length=255), nullable=True),
|
||||
sa.Column('ticket_link', sa.String(length=255), nullable=True),
|
||||
sa.Column('verified', sa.Boolean(), nullable=True),
|
||||
sa.Column('photo_id', sa.Integer(), nullable=True),
|
||||
sa.Column('created_by_id', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['admin_unit_id'], ['adminunit.id'], ),
|
||||
sa.ForeignKeyConstraint(['created_by_id'], ['user.id'], ),
|
||||
sa.ForeignKeyConstraint(['host_id'], ['org_or_adminunit.id'], ),
|
||||
sa.ForeignKeyConstraint(['photo_id'], ['image.id'], ),
|
||||
sa.ForeignKeyConstraint(['place_id'], ['place.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('eventsuggestiondate',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('event_suggestion_id', sa.Integer(), nullable=False),
|
||||
sa.Column('start', sa.DateTime(timezone=True), nullable=False),
|
||||
sa.ForeignKeyConstraint(['event_suggestion_id'], ['eventsuggestion.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
op.create_table('orgmemberroles_members',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('member_id', sa.Integer(), nullable=True),
|
||||
@ -244,20 +265,21 @@ def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_table('eventdate')
|
||||
op.drop_table('orgmemberroles_members')
|
||||
op.drop_table('eventsuggestiondate')
|
||||
op.drop_table('event')
|
||||
op.drop_table('adminunitorgroles_organizations')
|
||||
op.drop_table('adminunitmemberroles_members')
|
||||
op.drop_table('place')
|
||||
op.drop_table('orgmember')
|
||||
op.drop_table('org_or_adminunit')
|
||||
op.drop_table('eventsuggestion')
|
||||
op.drop_table('eventsuggestiondate')
|
||||
op.drop_table('adminunitorg')
|
||||
op.drop_table('adminunitmember')
|
||||
op.drop_table('adminunitmemberroles_members')
|
||||
op.drop_table('actor')
|
||||
op.drop_table('roles_users')
|
||||
op.drop_table('place')
|
||||
op.drop_table('organization')
|
||||
op.drop_table('eventsuggestion')
|
||||
op.drop_table('adminunitmember')
|
||||
op.drop_table('roles_users')
|
||||
op.drop_table('location')
|
||||
op.drop_table('image')
|
||||
op.drop_table('adminunit')
|
||||
op.drop_table('user')
|
||||
op.drop_table('role')
|
||||
23
models.py
23
models.py
@ -2,7 +2,7 @@ from app import db
|
||||
from sqlalchemy.ext.declarative import declared_attr
|
||||
from sqlalchemy.orm import relationship, backref
|
||||
from sqlalchemy.schema import CheckConstraint
|
||||
from sqlalchemy import UniqueConstraint, Boolean, DateTime, Column, Integer, String, ForeignKey, Unicode, UnicodeText, Numeric
|
||||
from sqlalchemy import UniqueConstraint, Boolean, DateTime, Column, Integer, String, ForeignKey, Unicode, UnicodeText, Numeric, LargeBinary
|
||||
from flask_security import UserMixin, RoleMixin
|
||||
import datetime
|
||||
|
||||
@ -19,6 +19,14 @@ class TrackableMixin(object):
|
||||
def created_by(cls):
|
||||
return relationship("User")
|
||||
|
||||
### Multi purpose
|
||||
|
||||
class Image(db.Model, TrackableMixin):
|
||||
__tablename__ = 'image'
|
||||
id = Column(Integer(), primary_key=True)
|
||||
data = db.Column(db.LargeBinary)
|
||||
encoding_format = Column(String(80))
|
||||
|
||||
### User
|
||||
|
||||
class RolesUsers(db.Model):
|
||||
@ -79,6 +87,12 @@ class Organization(db.Model, TrackableMixin):
|
||||
__tablename__ = 'organization'
|
||||
id = Column(Integer(), primary_key=True)
|
||||
name = Column(Unicode(255), unique=True)
|
||||
legal_name = 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)
|
||||
url = Column(String(255))
|
||||
members = relationship('OrgMember', backref=backref('organization', lazy=True))
|
||||
|
||||
### Admin Unit
|
||||
@ -135,6 +149,7 @@ class AdminUnit(db.Model, TrackableMixin):
|
||||
organizations = relationship('AdminUnitOrg', backref=backref('adminunit', lazy=True))
|
||||
|
||||
# Universal Types
|
||||
|
||||
class Actor(db.Model):
|
||||
__tablename__ = 'actor'
|
||||
__table_args__ = (UniqueConstraint('user_id', 'organization_id', 'admin_unit_id'),)
|
||||
@ -175,6 +190,10 @@ class Place(db.Model, TrackableMixin):
|
||||
name = Column(Unicode(255), nullable=False, unique=True)
|
||||
location_id = db.Column(db.Integer, db.ForeignKey('location.id'))
|
||||
location = db.relationship('Location')
|
||||
photo_id = db.Column(db.Integer, db.ForeignKey('image.id'))
|
||||
photo = db.relationship('Image', uselist=False)
|
||||
url = Column(String(255))
|
||||
description = Column(UnicodeText())
|
||||
|
||||
# Events
|
||||
class EventSuggestion(db.Model, TrackableMixin):
|
||||
@ -215,6 +234,8 @@ class Event(db.Model, TrackableMixin):
|
||||
external_link = Column(String(255))
|
||||
ticket_link = Column(String(255))
|
||||
verified = Column(Boolean())
|
||||
photo_id = db.Column(db.Integer, db.ForeignKey('image.id'))
|
||||
photo = db.relationship('Image', uselist=False)
|
||||
|
||||
dates = relationship('EventDate', backref=backref('event', lazy=False), cascade="all, delete-orphan")
|
||||
# wiederkehrende Dates sind zeitlich eingeschränkt
|
||||
|
||||
BIN
static/img/lotte.jpeg
Normal file
BIN
static/img/lotte.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
BIN
static/img/minersrock.jpeg
Normal file
BIN
static/img/minersrock.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
BIN
static/img/schlosserei.jpeg
Normal file
BIN
static/img/schlosserei.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 237 KiB |
@ -56,16 +56,14 @@
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro render_location(location) %}
|
||||
{{ location.street }}, {{ location.postalCode }} {{ location.city }}
|
||||
{% endmacro %}
|
||||
{% macro render_location(location) %}{{ location.street }}, {{ location.postalCode }} {{ location.city }}{% endmacro %}
|
||||
|
||||
{% macro render_place(place) %}
|
||||
{% if place.location %}
|
||||
{%- if place.location -%}
|
||||
{{ place.name }}, {{render_location(place.location)}}
|
||||
{% else %}
|
||||
{%- else -%}
|
||||
{{ place.name }}
|
||||
{% endif %}
|
||||
{%- endif -%}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro render_events_sub_menu(user_can_create_event, user_can_list_event_suggestion) %}
|
||||
@ -123,4 +121,44 @@
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{% endmacro %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro render_location_card(location, place=None) %}
|
||||
{% if location %}
|
||||
<div class="card card-body">
|
||||
<p>
|
||||
{{ location.street }}<br />
|
||||
{{ location.postalCode }} {{ location.city }}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="http://www.google.com/maps?q={% if place %}{{ render_place(place) | quote_plus }}{% else %}{{ render_location(location) | quote_plus }}{% endif %}">{{ _('Show on Google Maps') }}</a>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro render_link_prop(link) %}
|
||||
{% if link %}
|
||||
<div>
|
||||
<i class="fa fa-fw fa-external-link" data-toggle="tooltip" title="{{ _('Link') }}"></i>
|
||||
<a href="{{ link }}">{{ link }}</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro render_location_prop(location) %}
|
||||
{% if location %}
|
||||
<div>
|
||||
<i class="fa fa-fw fa-map-marker" data-toggle="tooltip" title="{{ _('Location') }}"></i>
|
||||
{{ render_location(location) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro render_image(image_id) %}
|
||||
{% if image_id %}
|
||||
<img src="{{ url_for('image', id=image_id) }}"/>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
@ -1,5 +1,5 @@
|
||||
{% extends "layout.html" %}
|
||||
{% from "_macros.html" import render_ooa_with_link, render_place %}
|
||||
{% from "_macros.html" import render_image, render_ooa_with_link, render_place, render_link_prop %}
|
||||
{% block title %}
|
||||
{{ event.name }}
|
||||
{% endblock %}
|
||||
@ -29,14 +29,18 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if event.photo_id %}
|
||||
<div class="my-4">{{ render_image(event.photo_id) }}</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="my-4">{{ event.description }}</div>
|
||||
|
||||
{% if event.external_link %}
|
||||
<div class="my-4">
|
||||
<i class="fa fa-fw fa-external-link" data-toggle="tooltip" title="{{ _('Link') }}"></i>
|
||||
<a href="{{ event.external_link }}">{{ event.external_link }}</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if event.external_link or event.ticket_link %}
|
||||
<div class="my-4">
|
||||
{{ render_link_prop(event.external_link) }}
|
||||
{{ render_link_prop(event.ticket_link) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="my-4">
|
||||
<div><i class="fa fa-fw fa-users" data-toggle="tooltip" title="{{ _('Host') }}"></i> {{ render_ooa_with_link(event.host) }}</div>
|
||||
|
||||
@ -56,6 +56,7 @@
|
||||
<a class="nav-item nav-link" href="{{ url_for('admin_units') }}">{{ _('Admin Units') }}</a>
|
||||
<a class="nav-item nav-link" href="{{ url_for('organizations') }}">{{ _('Organizations') }}</a>
|
||||
<a class="nav-item nav-link" href="{{ url_for('events') }}">{{ _('Events') }}</a>
|
||||
<a class="nav-item nav-link" href="{{ url_for('places') }}">{{ _('Places') }}</a>
|
||||
</div>
|
||||
<div class="navbar-nav navbar-right">
|
||||
{% if current_user.is_authenticated %}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{% extends "layout.html" %}
|
||||
{% from "_macros.html" import render_events %}
|
||||
{% from "_macros.html" import render_events, render_location_prop, render_link_prop, render_image %}
|
||||
{% block title %}
|
||||
{{ organization.name }}
|
||||
{% endblock %}
|
||||
@ -9,24 +9,40 @@
|
||||
|
||||
<!-- Nav tabs -->
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" data-toggle="tab" href="#info" role="tab" area-selected="true">{{ _('Info') }}</a>
|
||||
</li>
|
||||
{% if current_user_member or can_list_members %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" data-toggle="tab" href="#members" role="tab" area-selected="true">{{ _('Members') }}</a>
|
||||
<a class="nav-link" data-toggle="tab" href="#members" role="tab">{{ _('Members') }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="tab" href="#events" role="tab">{{ _('Events') }}</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" data-toggle="tab" href="#events" role="tab" area-selected="true">{{ _('Events') }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
||||
<!-- Tab panes -->
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane pt-4 active" id="info" role="tabpanel">
|
||||
|
||||
{% if organization.legal_name %}
|
||||
<div>{{ organization.legal_name }}</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="my-4">
|
||||
{{ render_location_prop(organization.location) }}
|
||||
{{ render_link_prop(organization.url) }}
|
||||
</div>
|
||||
|
||||
{% if organization.logo_id %}
|
||||
<div class="my-4">{{ render_image(organization.logo_id) }}</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
{% if current_user_member or can_list_members %}
|
||||
<div class="tab-pane pt-4 active" id="members" role="tabpanel">
|
||||
<div class="tab-pane pt-4" id="members" role="tabpanel">
|
||||
{% if current_user_member %}
|
||||
<div class="my-4">
|
||||
{{ _('You are a member of this organization.') }}
|
||||
@ -56,7 +72,8 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="tab-pane pt-4{% if not current_user_member and not can_list_members %} active{% endif %}" id="events" role="tabpanel">
|
||||
|
||||
<div class="tab-pane pt-4" id="events" role="tabpanel">
|
||||
{{ render_events(events) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
28
templates/place/list.html
Normal file
28
templates/place/list.html
Normal file
@ -0,0 +1,28 @@
|
||||
{% extends "layout.html" %}
|
||||
{% block title %}
|
||||
{{ _('Places') }}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
|
||||
<h1>{{ _('Places') }}</h1>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm table-bordered table-hover table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ _('Name') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for place in places %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ url_for('place', place_id=place.id) }}">{{ place.name }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@ -1,5 +1,5 @@
|
||||
{% extends "layout.html" %}
|
||||
{% from "_macros.html" import render_place, render_events %}
|
||||
{% from "_macros.html" import render_place, render_events, render_location_card, render_link_prop, render_image %}
|
||||
{% block title %}
|
||||
{{ place.name }}
|
||||
{% endblock %}
|
||||
@ -7,21 +7,39 @@
|
||||
|
||||
<h1>{{ place.name }}</h1>
|
||||
|
||||
{% if place.location %}
|
||||
<div class="card card-body">
|
||||
<p>
|
||||
{{ place.location.street }}<br />
|
||||
{{ place.location.postalCode }} {{ place.location.city }}
|
||||
</p>
|
||||
<!-- Nav tabs -->
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" data-toggle="tab" href="#info" role="tab" area-selected="true">{{ _('Info') }}</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="tab" href="#events" role="tab">{{ _('Events') }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
<a href="http://www.google.com/maps?q={{ render_place(place) | quote_plus }}">{{ _('Show on Google Maps') }}</a>
|
||||
</p>
|
||||
<!-- Tab panes -->
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane pt-4 active" id="info" role="tabpanel">
|
||||
|
||||
{{ render_location_card(place.location, place) }}
|
||||
|
||||
<div class="my-4">
|
||||
{{ render_link_prop(place.url) }}
|
||||
</div>
|
||||
|
||||
{% if place.photo_id %}
|
||||
<div class="my-4">{{ render_image(place.photo_id) }}</div>
|
||||
{% endif %}
|
||||
|
||||
{% if place.description %}
|
||||
<div class="my-4">{{ place.description }}</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
<div class="tab-pane pt-4" id="events" role="tabpanel">
|
||||
{{ render_events(place.events) }}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<h2>{{ _('Events') }}</h2>
|
||||
{{ render_events(place.events) }}
|
||||
|
||||
{% endblock %}
|
||||
Loading…
x
Reference in New Issue
Block a user