Internal/analysis (#4)

* Codestyle Black

* Flake8

* Test coverage
This commit is contained in:
Daniel Grams 2020-11-13 23:05:39 +01:00 committed by GitHub
parent d63f340384
commit 273b3fb072
105 changed files with 4119 additions and 2224 deletions

14
.flake8 Normal file
View File

@ -0,0 +1,14 @@
[flake8]
extend-ignore = E501, E203
exclude =
.git,
.github,
.pytest_cache,
.vscode,
__pycache__,
doc,
env,
tmp
per-file-ignores =
__init__.py: F401, E402
migrations/*: F401, E402

12
.github/workflows/lint.yml vendored Normal file
View File

@ -0,0 +1,12 @@
name: Lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- uses: psf/black@stable
- uses: TrueBrain/actions-flake8@v1.4.1

10
.pre-commit-config.yaml Normal file
View File

@ -0,0 +1,10 @@
repos:
- repo: https://github.com/psf/black
rev: stable
hooks:
- id: black
language_version: python3.7
- repo: https://gitlab.com/pycqa/flake8
rev: 3.8.4
hooks:
- id: flake8

View File

@ -15,4 +15,6 @@ before_script:
- psql -c 'create database gsevpt_tests;' -U postgres - psql -c 'create database gsevpt_tests;' -U postgres
- psql -c 'create extension postgis;' -U postgres -d gsevpt_tests - psql -c 'create extension postgis;' -U postgres -d gsevpt_tests
script: script:
- pytest - pytest --cov=project
after_success:
— coveralls

View File

@ -1,3 +1,7 @@
{ {
"python.pythonPath": "/Users/daniel/Projects/gsevpt/env/bin/python3" "python.pythonPath": "/Users/daniel/Projects/gsevpt/env/bin/python3",
"python.formatting.provider": "black",
"python.linting.enabled": true,
"python.linting.pylintEnabled": false,
"python.linting.flake8Enabled": true
} }

View File

@ -1,7 +1,7 @@
[![Build Status](https://travis-ci.com/DanielGrams/gsevpt.svg?branch=master)](https://travis-ci.com/DanielGrams/gsevpt)
# Goslar Event Prototype # Goslar Event Prototype
[![Build Status](https://travis-ci.com/DanielGrams/gsevpt.svg?branch=master)](https://travis-ci.com/DanielGrams/gsevpt) [![Coverage Status](https://coveralls.io/repos/github/DanielGrams/gsevpt/badge.svg?branch=master)](https://coveralls.io/github/DanielGrams/gsevpt?branch=master) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
Website prototype using Python, Flask and Postgres running on Heroku. Website prototype using Python, Flask and Postgres running on Heroku.
## Automatic Deployment ## Automatic Deployment
@ -67,4 +67,4 @@ Create `.env` file in the root directory or pass as environment variables.
## Development ## Development
[Development](doc/development.md) [Development](doc/development.md)

View File

@ -1 +1 @@
from project import app from project import app # noqa: F401

View File

@ -15,6 +15,12 @@ psql -c 'create extension postgis;' -d gsevpt_tests -U postgres
pytest pytest
``` ```
With coverage:
```sh
pytest --cov-report=html --cov=project
```
## Database ## Database
### Create new revision ### Create new revision

View File

@ -1,11 +1,11 @@
from flask_script import Manager, Command from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand from flask_migrate import Migrate, MigrateCommand
from project import app, db from project import app, db
migrate = Migrate(app, db) migrate = Migrate(app, db)
manager = Manager(app) manager = Manager(app)
manager.add_command('db', MigrateCommand) manager.add_command("db", MigrateCommand)
if __name__ == '__main__': if __name__ == "__main__":
manager.run() manager.run()

View File

@ -15,17 +15,19 @@ config = context.config
# Interpret the config file for Python logging. # Interpret the config file for Python logging.
# This line sets up loggers basically. # This line sets up loggers basically.
fileConfig(config.config_file_name) fileConfig(config.config_file_name)
logger = logging.getLogger('alembic.env') logger = logging.getLogger("alembic.env")
# add your model's MetaData object here # add your model's MetaData object here
# for 'autogenerate' support # for 'autogenerate' support
# from myapp import mymodel # from myapp import mymodel
# target_metadata = mymodel.Base.metadata # target_metadata = mymodel.Base.metadata
from flask import current_app from flask import current_app
config.set_main_option( config.set_main_option(
'sqlalchemy.url', "sqlalchemy.url",
str(current_app.extensions['migrate'].db.engine.url).replace('%', '%%')) str(current_app.extensions["migrate"].db.engine.url).replace("%", "%%"),
target_metadata = current_app.extensions['migrate'].db.metadata )
target_metadata = current_app.extensions["migrate"].db.metadata
# other values from the config, defined by the needs of env.py, # other values from the config, defined by the needs of env.py,
# can be acquired: # can be acquired:
@ -46,9 +48,7 @@ def run_migrations_offline():
""" """
url = config.get_main_option("sqlalchemy.url") url = config.get_main_option("sqlalchemy.url")
context.configure( context.configure(url=url, target_metadata=target_metadata, literal_binds=True)
url=url, target_metadata=target_metadata, literal_binds=True
)
with context.begin_transaction(): with context.begin_transaction():
context.run_migrations() context.run_migrations()
@ -66,15 +66,15 @@ def run_migrations_online():
# when there are no changes to the schema # when there are no changes to the schema
# reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
def process_revision_directives(context, revision, directives): def process_revision_directives(context, revision, directives):
if getattr(config.cmd_opts, 'autogenerate', False): if getattr(config.cmd_opts, "autogenerate", False):
script = directives[0] script = directives[0]
if script.upgrade_ops.is_empty(): if script.upgrade_ops.is_empty():
directives[:] = [] directives[:] = []
logger.info('No changes in schema detected.') logger.info("No changes in schema detected.")
connectable = engine_from_config( connectable = engine_from_config(
config.get_section(config.config_ini_section), config.get_section(config.config_ini_section),
prefix='sqlalchemy.', prefix="sqlalchemy.",
poolclass=pool.NullPool, poolclass=pool.NullPool,
) )
@ -83,7 +83,7 @@ def run_migrations_online():
connection=connection, connection=connection,
target_metadata=target_metadata, target_metadata=target_metadata,
process_revision_directives=process_revision_directives, process_revision_directives=process_revision_directives,
**current_app.extensions['migrate'].configure_args **current_app.extensions["migrate"].configure_args
) )
with context.begin_transaction(): with context.begin_transaction():

View File

@ -12,31 +12,50 @@ from project import dbtypes
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '00daa8c472ba' revision = "00daa8c472ba"
down_revision = '50337ecd23db' down_revision = "50337ecd23db"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
#op.drop_table('spatial_ref_sys') # op.drop_table('spatial_ref_sys')
op.drop_constraint('eventsuggestion_event_id_fkey', 'eventsuggestion', type_='foreignkey') op.drop_constraint(
op.create_foreign_key(None, 'eventsuggestion', 'event', ['event_id'], ['id'], ondelete='SET NULL') "eventsuggestion_event_id_fkey", "eventsuggestion", type_="foreignkey"
)
op.create_foreign_key(
None, "eventsuggestion", "event", ["event_id"], ["id"], ondelete="SET NULL"
)
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'eventsuggestion', type_='foreignkey') op.drop_constraint(None, "eventsuggestion", type_="foreignkey")
op.create_foreign_key('eventsuggestion_event_id_fkey', 'eventsuggestion', 'event', ['event_id'], ['id']) op.create_foreign_key(
op.create_table('spatial_ref_sys', "eventsuggestion_event_id_fkey",
sa.Column('srid', sa.INTEGER(), autoincrement=False, nullable=False), "eventsuggestion",
sa.Column('auth_name', sa.VARCHAR(length=256), autoincrement=False, nullable=True), "event",
sa.Column('auth_srid', sa.INTEGER(), autoincrement=False, nullable=True), ["event_id"],
sa.Column('srtext', sa.VARCHAR(length=2048), autoincrement=False, nullable=True), ["id"],
sa.Column('proj4text', sa.VARCHAR(length=2048), autoincrement=False, nullable=True), )
sa.CheckConstraint('(srid > 0) AND (srid <= 998999)', name='spatial_ref_sys_srid_check'), op.create_table(
sa.PrimaryKeyConstraint('srid', name='spatial_ref_sys_pkey') "spatial_ref_sys",
sa.Column("srid", sa.INTEGER(), autoincrement=False, nullable=False),
sa.Column(
"auth_name", sa.VARCHAR(length=256), autoincrement=False, nullable=True
),
sa.Column("auth_srid", sa.INTEGER(), autoincrement=False, nullable=True),
sa.Column(
"srtext", sa.VARCHAR(length=2048), autoincrement=False, nullable=True
),
sa.Column(
"proj4text", sa.VARCHAR(length=2048), autoincrement=False, nullable=True
),
sa.CheckConstraint(
"(srid > 0) AND (srid <= 998999)", name="spatial_ref_sys_srid_check"
),
sa.PrimaryKeyConstraint("srid", name="spatial_ref_sys_pkey"),
) )
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -12,68 +12,117 @@ from project import dbtypes
from project.models import EventRejectionReason, EventReviewStatus from project.models import EventRejectionReason, EventReviewStatus
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '021f602d9965' revision = "021f602d9965"
down_revision = '92f37474ad62' down_revision = "92f37474ad62"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.create_table('eventsuggestion', op.create_table(
sa.Column('created_at', sa.DateTime(), nullable=True), "eventsuggestion",
sa.Column('id', sa.Integer(), nullable=False), sa.Column("created_at", sa.DateTime(), nullable=True),
sa.Column('name', sa.Unicode(length=255), nullable=False), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('start', sa.DateTime(timezone=True), nullable=False), sa.Column("name", sa.Unicode(length=255), nullable=False),
sa.Column('description', sa.UnicodeText(), nullable=True), sa.Column("start", sa.DateTime(timezone=True), nullable=False),
sa.Column('external_link', sa.String(length=255), nullable=True), sa.Column("description", sa.UnicodeText(), nullable=True),
sa.Column('review_status', dbtypes.IntegerEnum(EventReviewStatus), nullable=True), sa.Column("external_link", sa.String(length=255), nullable=True),
sa.Column('rejection_resaon', dbtypes.IntegerEnum(EventRejectionReason), nullable=True), sa.Column(
sa.Column('contact_name', sa.Unicode(length=255), nullable=False), "review_status", dbtypes.IntegerEnum(EventReviewStatus), nullable=True
sa.Column('contact_email', sa.Unicode(length=255), nullable=True), ),
sa.Column('contact_phone', sa.Unicode(length=255), nullable=True), sa.Column(
sa.Column('admin_unit_id', sa.Integer(), nullable=False), "rejection_resaon", dbtypes.IntegerEnum(EventRejectionReason), nullable=True
sa.Column('event_place_id', sa.Integer(), nullable=True), ),
sa.Column('event_place_text', sa.Unicode(length=255), nullable=True), sa.Column("contact_name", sa.Unicode(length=255), nullable=False),
sa.Column('organizer_id', sa.Integer(), nullable=True), sa.Column("contact_email", sa.Unicode(length=255), nullable=True),
sa.Column('organizer_text', sa.Unicode(length=255), nullable=True), sa.Column("contact_phone", sa.Unicode(length=255), nullable=True),
sa.Column('photo_id', sa.Integer(), nullable=True), sa.Column("admin_unit_id", sa.Integer(), nullable=False),
sa.Column('created_by_id', sa.Integer(), nullable=True), sa.Column("event_place_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['admin_unit_id'], ['adminunit.id'], ), sa.Column("event_place_text", sa.Unicode(length=255), nullable=True),
sa.ForeignKeyConstraint(['created_by_id'], ['user.id'], ), sa.Column("organizer_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['event_place_id'], ['eventplace.id'], ), sa.Column("organizer_text", sa.Unicode(length=255), nullable=True),
sa.ForeignKeyConstraint(['organizer_id'], ['eventorganizer.id'], ), sa.Column("photo_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['photo_id'], ['image.id'], ), sa.Column("created_by_id", sa.Integer(), nullable=True),
sa.PrimaryKeyConstraint('id') sa.ForeignKeyConstraint(
["admin_unit_id"],
["adminunit.id"],
),
sa.ForeignKeyConstraint(
["created_by_id"],
["user.id"],
),
sa.ForeignKeyConstraint(
["event_place_id"],
["eventplace.id"],
),
sa.ForeignKeyConstraint(
["organizer_id"],
["eventorganizer.id"],
),
sa.ForeignKeyConstraint(
["photo_id"],
["image.id"],
),
sa.PrimaryKeyConstraint("id"),
) )
#op.drop_table('spatial_ref_sys') # op.drop_table('spatial_ref_sys')
op.drop_constraint('event_contact_id_fkey', 'event', type_='foreignkey') op.drop_constraint("event_contact_id_fkey", "event", type_="foreignkey")
op.drop_column('event', 'review_status') op.drop_column("event", "review_status")
op.drop_column('event', 'rejection_resaon') op.drop_column("event", "rejection_resaon")
op.drop_column('event', 'contact_id') op.drop_column("event", "contact_id")
op.drop_column('eventcontact', 'email') op.drop_column("eventcontact", "email")
op.drop_column('eventcontact', 'name') op.drop_column("eventcontact", "name")
op.drop_column('eventcontact', 'phone') op.drop_column("eventcontact", "phone")
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.add_column('eventcontact', sa.Column('phone', sa.VARCHAR(length=255), autoincrement=False, nullable=True)) op.add_column(
op.add_column('eventcontact', sa.Column('name', sa.VARCHAR(length=255), autoincrement=False, nullable=False)) "eventcontact",
op.add_column('eventcontact', sa.Column('email', sa.VARCHAR(length=255), autoincrement=False, nullable=True)) sa.Column("phone", sa.VARCHAR(length=255), autoincrement=False, nullable=True),
op.add_column('event', sa.Column('contact_id', sa.INTEGER(), autoincrement=False, nullable=True))
op.add_column('event', sa.Column('rejection_resaon', sa.INTEGER(), autoincrement=False, nullable=True))
op.add_column('event', sa.Column('review_status', sa.INTEGER(), autoincrement=False, nullable=True))
op.create_foreign_key('event_contact_id_fkey', 'event', 'eventcontact', ['contact_id'], ['id'])
op.create_table('spatial_ref_sys',
sa.Column('srid', sa.INTEGER(), autoincrement=False, nullable=False),
sa.Column('auth_name', sa.VARCHAR(length=256), autoincrement=False, nullable=True),
sa.Column('auth_srid', sa.INTEGER(), autoincrement=False, nullable=True),
sa.Column('srtext', sa.VARCHAR(length=2048), autoincrement=False, nullable=True),
sa.Column('proj4text', sa.VARCHAR(length=2048), autoincrement=False, nullable=True),
sa.CheckConstraint('(srid > 0) AND (srid <= 998999)', name='spatial_ref_sys_srid_check'),
sa.PrimaryKeyConstraint('srid', name='spatial_ref_sys_pkey')
) )
op.drop_table('eventsuggestion') op.add_column(
"eventcontact",
sa.Column("name", sa.VARCHAR(length=255), autoincrement=False, nullable=False),
)
op.add_column(
"eventcontact",
sa.Column("email", sa.VARCHAR(length=255), autoincrement=False, nullable=True),
)
op.add_column(
"event",
sa.Column("contact_id", sa.INTEGER(), autoincrement=False, nullable=True),
)
op.add_column(
"event",
sa.Column("rejection_resaon", sa.INTEGER(), autoincrement=False, nullable=True),
)
op.add_column(
"event",
sa.Column("review_status", sa.INTEGER(), autoincrement=False, nullable=True),
)
op.create_foreign_key(
"event_contact_id_fkey", "event", "eventcontact", ["contact_id"], ["id"]
)
op.create_table(
"spatial_ref_sys",
sa.Column("srid", sa.INTEGER(), autoincrement=False, nullable=False),
sa.Column(
"auth_name", sa.VARCHAR(length=256), autoincrement=False, nullable=True
),
sa.Column("auth_srid", sa.INTEGER(), autoincrement=False, nullable=True),
sa.Column(
"srtext", sa.VARCHAR(length=2048), autoincrement=False, nullable=True
),
sa.Column(
"proj4text", sa.VARCHAR(length=2048), autoincrement=False, nullable=True
),
sa.CheckConstraint(
"(srid > 0) AND (srid <= 998999)", name="spatial_ref_sys_srid_check"
),
sa.PrimaryKeyConstraint("srid", name="spatial_ref_sys_pkey"),
)
op.drop_table("eventsuggestion")
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -8,14 +8,12 @@ Create Date: 2020-10-02 09:29:12.932229
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy.sql import text from sqlalchemy.sql import text
import sqlalchemy_utils
from project import dbtypes
from geoalchemy2.types import Geometry from geoalchemy2.types import Geometry
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '091deace5f08' revision = "091deace5f08"
down_revision = '6b7016f73688' down_revision = "6b7016f73688"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
@ -26,21 +24,39 @@ def upgrade():
bind.execute(text("create extension if not exists postgis;")) bind.execute(text("create extension if not exists postgis;"))
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
#op.drop_table('spatial_ref_sys') # op.drop_table('spatial_ref_sys')
op.add_column('location', sa.Column('coordinate', Geometry(geometry_type='POINT', from_text='ST_GeomFromEWKT', name='geometry'), nullable=True)) op.add_column(
"location",
sa.Column(
"coordinate",
Geometry(
geometry_type="POINT", from_text="ST_GeomFromEWKT", name="geometry"
),
nullable=True,
),
)
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_column('location', 'coordinate') op.drop_column("location", "coordinate")
op.create_table('spatial_ref_sys', op.create_table(
sa.Column('srid', sa.INTEGER(), autoincrement=False, nullable=False), "spatial_ref_sys",
sa.Column('auth_name', sa.VARCHAR(length=256), autoincrement=False, nullable=True), sa.Column("srid", sa.INTEGER(), autoincrement=False, nullable=False),
sa.Column('auth_srid', sa.INTEGER(), autoincrement=False, nullable=True), sa.Column(
sa.Column('srtext', sa.VARCHAR(length=2048), autoincrement=False, nullable=True), "auth_name", sa.VARCHAR(length=256), autoincrement=False, nullable=True
sa.Column('proj4text', sa.VARCHAR(length=2048), autoincrement=False, nullable=True), ),
sa.CheckConstraint('(srid > 0) AND (srid <= 998999)', name='spatial_ref_sys_srid_check'), sa.Column("auth_srid", sa.INTEGER(), autoincrement=False, nullable=True),
sa.PrimaryKeyConstraint('srid', name='spatial_ref_sys_pkey') sa.Column(
"srtext", sa.VARCHAR(length=2048), autoincrement=False, nullable=True
),
sa.Column(
"proj4text", sa.VARCHAR(length=2048), autoincrement=False, nullable=True
),
sa.CheckConstraint(
"(srid > 0) AND (srid <= 998999)", name="spatial_ref_sys_srid_check"
),
sa.PrimaryKeyConstraint("srid", name="spatial_ref_sys_pkey"),
) )
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -12,35 +12,48 @@ from project import dbtypes
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '0a282a331e35' revision = "0a282a331e35"
down_revision = 'da63ba1d58b1' down_revision = "da63ba1d58b1"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
#op.drop_table('spatial_ref_sys') # op.drop_table('spatial_ref_sys')
op.add_column('event', sa.Column('booked_up', sa.Boolean(), nullable=True)) op.add_column("event", sa.Column("booked_up", sa.Boolean(), nullable=True))
op.add_column('event', sa.Column('expected_participants', sa.Integer(), nullable=True)) op.add_column(
op.add_column('event', sa.Column('price_info', sa.UnicodeText(), nullable=True)) "event", sa.Column("expected_participants", sa.Integer(), nullable=True)
op.add_column('event', sa.Column('registration_required', sa.Boolean(), nullable=True)) )
op.add_column("event", sa.Column("price_info", sa.UnicodeText(), nullable=True))
op.add_column(
"event", sa.Column("registration_required", sa.Boolean(), nullable=True)
)
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_column('event', 'registration_required') op.drop_column("event", "registration_required")
op.drop_column('event', 'price_info') op.drop_column("event", "price_info")
op.drop_column('event', 'expected_participants') op.drop_column("event", "expected_participants")
op.drop_column('event', 'booked_up') op.drop_column("event", "booked_up")
op.create_table('spatial_ref_sys', op.create_table(
sa.Column('srid', sa.INTEGER(), autoincrement=False, nullable=False), "spatial_ref_sys",
sa.Column('auth_name', sa.VARCHAR(length=256), autoincrement=False, nullable=True), sa.Column("srid", sa.INTEGER(), autoincrement=False, nullable=False),
sa.Column('auth_srid', sa.INTEGER(), autoincrement=False, nullable=True), sa.Column(
sa.Column('srtext', sa.VARCHAR(length=2048), autoincrement=False, nullable=True), "auth_name", sa.VARCHAR(length=256), autoincrement=False, nullable=True
sa.Column('proj4text', sa.VARCHAR(length=2048), autoincrement=False, nullable=True), ),
sa.CheckConstraint('(srid > 0) AND (srid <= 998999)', name='spatial_ref_sys_srid_check'), sa.Column("auth_srid", sa.INTEGER(), autoincrement=False, nullable=True),
sa.PrimaryKeyConstraint('srid', name='spatial_ref_sys_pkey') sa.Column(
"srtext", sa.VARCHAR(length=2048), autoincrement=False, nullable=True
),
sa.Column(
"proj4text", sa.VARCHAR(length=2048), autoincrement=False, nullable=True
),
sa.CheckConstraint(
"(srid > 0) AND (srid <= 998999)", name="spatial_ref_sys_srid_check"
),
sa.PrimaryKeyConstraint("srid", name="spatial_ref_sys_pkey"),
) )
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -8,39 +8,70 @@ Create Date: 2020-11-08 16:14:01.866196
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
import sqlalchemy_utils import sqlalchemy_utils
from project import dbtypes
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '27da3ceea723' revision = "27da3ceea723"
down_revision = '00daa8c472ba' down_revision = "00daa8c472ba"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
#op.drop_table('spatial_ref_sys') # op.drop_table('spatial_ref_sys')
op.add_column('adminunit', sa.Column('widget_background_color', sqlalchemy_utils.types.color.ColorType(length=20), nullable=True)) op.add_column(
op.add_column('adminunit', sa.Column('widget_font', sa.Unicode(length=255), nullable=True)) "adminunit",
op.add_column('adminunit', sa.Column('widget_link_color', sqlalchemy_utils.types.color.ColorType(length=20), nullable=True)) sa.Column(
op.add_column('adminunit', sa.Column('widget_primary_color', sqlalchemy_utils.types.color.ColorType(length=20), nullable=True)) "widget_background_color",
sqlalchemy_utils.types.color.ColorType(length=20),
nullable=True,
),
)
op.add_column(
"adminunit", sa.Column("widget_font", sa.Unicode(length=255), nullable=True)
)
op.add_column(
"adminunit",
sa.Column(
"widget_link_color",
sqlalchemy_utils.types.color.ColorType(length=20),
nullable=True,
),
)
op.add_column(
"adminunit",
sa.Column(
"widget_primary_color",
sqlalchemy_utils.types.color.ColorType(length=20),
nullable=True,
),
)
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_column('adminunit', 'widget_primary_color') op.drop_column("adminunit", "widget_primary_color")
op.drop_column('adminunit', 'widget_link_color') op.drop_column("adminunit", "widget_link_color")
op.drop_column('adminunit', 'widget_font') op.drop_column("adminunit", "widget_font")
op.drop_column('adminunit', 'widget_background_color') op.drop_column("adminunit", "widget_background_color")
op.create_table('spatial_ref_sys', op.create_table(
sa.Column('srid', sa.INTEGER(), autoincrement=False, nullable=False), "spatial_ref_sys",
sa.Column('auth_name', sa.VARCHAR(length=256), autoincrement=False, nullable=True), sa.Column("srid", sa.INTEGER(), autoincrement=False, nullable=False),
sa.Column('auth_srid', sa.INTEGER(), autoincrement=False, nullable=True), sa.Column(
sa.Column('srtext', sa.VARCHAR(length=2048), autoincrement=False, nullable=True), "auth_name", sa.VARCHAR(length=256), autoincrement=False, nullable=True
sa.Column('proj4text', sa.VARCHAR(length=2048), autoincrement=False, nullable=True), ),
sa.CheckConstraint('(srid > 0) AND (srid <= 998999)', name='spatial_ref_sys_srid_check'), sa.Column("auth_srid", sa.INTEGER(), autoincrement=False, nullable=True),
sa.PrimaryKeyConstraint('srid', name='spatial_ref_sys_pkey') sa.Column(
"srtext", sa.VARCHAR(length=2048), autoincrement=False, nullable=True
),
sa.Column(
"proj4text", sa.VARCHAR(length=2048), autoincrement=False, nullable=True
),
sa.CheckConstraint(
"(srid > 0) AND (srid <= 998999)", name="spatial_ref_sys_srid_check"
),
sa.PrimaryKeyConstraint("srid", name="spatial_ref_sys_pkey"),
) )
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -13,49 +13,65 @@ from project import dbtypes
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '3c5b34fd1156' revision = "3c5b34fd1156"
down_revision = '27da3ceea723' down_revision = "27da3ceea723"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
Base = declarative_base() Base = declarative_base()
class Event(Base): class Event(Base):
__tablename__ = 'event' __tablename__ = "event"
id = sa.Column(sa.Integer(), primary_key=True) id = sa.Column(sa.Integer(), primary_key=True)
category_id = sa.Column(sa.Integer, sa.ForeignKey('eventcategory.id'), nullable=False) category_id = sa.Column(
category = orm.relationship('EventCategory', uselist=False) sa.Integer, sa.ForeignKey("eventcategory.id"), nullable=False
categories = orm.relationship('EventCategory', secondary='event_eventcategories') )
category = orm.relationship("EventCategory", uselist=False)
categories = orm.relationship("EventCategory", secondary="event_eventcategories")
class EventEventCategories(Base): class EventEventCategories(Base):
__tablename__ = 'event_eventcategories' __tablename__ = "event_eventcategories"
id = sa.Column(sa.Integer(), primary_key=True) id = sa.Column(sa.Integer(), primary_key=True)
event_id = sa.Column(sa.Integer, sa.ForeignKey('event.id'), nullable=False) event_id = sa.Column(sa.Integer, sa.ForeignKey("event.id"), nullable=False)
category_id = sa.Column(sa.Integer, sa.ForeignKey('eventcategory.id'), nullable=False) category_id = sa.Column(
sa.Integer, sa.ForeignKey("eventcategory.id"), nullable=False
)
class EventCategory(Base): class EventCategory(Base):
__tablename__ = 'eventcategory' __tablename__ = "eventcategory"
id = sa.Column(sa.Integer(), primary_key=True) id = sa.Column(sa.Integer(), primary_key=True)
name = sa.Column(sa.Unicode(255), nullable=False, unique=True) name = sa.Column(sa.Unicode(255), nullable=False, unique=True)
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.create_table('event_eventcategories', op.create_table(
sa.Column('id', sa.Integer(), nullable=False), "event_eventcategories",
sa.Column('event_id', sa.Integer(), nullable=False), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('category_id', sa.Integer(), nullable=False), sa.Column("event_id", sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['category_id'], ['eventcategory.id'], ), sa.Column("category_id", sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['event_id'], ['event.id'], ), sa.ForeignKeyConstraint(
sa.PrimaryKeyConstraint('id') ["category_id"],
["eventcategory.id"],
),
sa.ForeignKeyConstraint(
["event_id"],
["event.id"],
),
sa.PrimaryKeyConstraint("id"),
) )
migrate_category_to_categories() migrate_category_to_categories()
#op.drop_table('spatial_ref_sys') # op.drop_table('spatial_ref_sys')
op.drop_constraint('event_category_id_fkey', 'event', type_='foreignkey') op.drop_constraint("event_category_id_fkey", "event", type_="foreignkey")
op.drop_column('event', 'category_id') op.drop_column("event", "category_id")
# ### end Alembic commands ### # ### end Alembic commands ###
def migrate_category_to_categories(): def migrate_category_to_categories():
bind = op.get_bind() bind = op.get_bind()
session = orm.Session(bind=bind) session = orm.Session(bind=bind)
@ -65,18 +81,33 @@ def migrate_category_to_categories():
session.commit() session.commit()
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.add_column('event', sa.Column('category_id', sa.INTEGER(), autoincrement=False, nullable=False)) op.add_column(
op.create_foreign_key('event_category_id_fkey', 'event', 'eventcategory', ['category_id'], ['id']) "event",
op.create_table('spatial_ref_sys', sa.Column("category_id", sa.INTEGER(), autoincrement=False, nullable=False),
sa.Column('srid', sa.INTEGER(), autoincrement=False, nullable=False),
sa.Column('auth_name', sa.VARCHAR(length=256), autoincrement=False, nullable=True),
sa.Column('auth_srid', sa.INTEGER(), autoincrement=False, nullable=True),
sa.Column('srtext', sa.VARCHAR(length=2048), autoincrement=False, nullable=True),
sa.Column('proj4text', sa.VARCHAR(length=2048), autoincrement=False, nullable=True),
sa.CheckConstraint('(srid > 0) AND (srid <= 998999)', name='spatial_ref_sys_srid_check'),
sa.PrimaryKeyConstraint('srid', name='spatial_ref_sys_pkey')
) )
op.drop_table('event_eventcategories') op.create_foreign_key(
"event_category_id_fkey", "event", "eventcategory", ["category_id"], ["id"]
)
op.create_table(
"spatial_ref_sys",
sa.Column("srid", sa.INTEGER(), autoincrement=False, nullable=False),
sa.Column(
"auth_name", sa.VARCHAR(length=256), autoincrement=False, nullable=True
),
sa.Column("auth_srid", sa.INTEGER(), autoincrement=False, nullable=True),
sa.Column(
"srtext", sa.VARCHAR(length=2048), autoincrement=False, nullable=True
),
sa.Column(
"proj4text", sa.VARCHAR(length=2048), autoincrement=False, nullable=True
),
sa.CheckConstraint(
"(srid > 0) AND (srid <= 998999)", name="spatial_ref_sys_srid_check"
),
sa.PrimaryKeyConstraint("srid", name="spatial_ref_sys_pkey"),
)
op.drop_table("event_eventcategories")
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -12,21 +12,23 @@ from project import dbtypes
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '41512b20e07c' revision = "41512b20e07c"
down_revision = 'fd7794ece0b3' down_revision = "fd7794ece0b3"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint('event_event_place_id_fkey', 'event', type_='foreignkey') op.drop_constraint("event_event_place_id_fkey", "event", type_="foreignkey")
op.create_foreign_key(None, 'event', 'eventplace', ['event_place_id'], ['id']) op.create_foreign_key(None, "event", "eventplace", ["event_place_id"], ["id"])
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'event', type_='foreignkey') op.drop_constraint(None, "event", type_="foreignkey")
op.create_foreign_key('event_event_place_id_fkey', 'event', 'place', ['event_place_id'], ['id']) op.create_foreign_key(
"event_event_place_id_fkey", "event", "place", ["event_place_id"], ["id"]
)
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -12,25 +12,26 @@ from project import dbtypes
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '4e913af88c33' revision = "4e913af88c33"
down_revision = '67216b6cf293' down_revision = "67216b6cf293"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.create_table('analytics', op.create_table(
sa.Column('id', sa.Integer(), nullable=False), "analytics",
sa.Column('key', sa.Unicode(length=255), nullable=True), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('value', sa.UnicodeText(), nullable=True), sa.Column("key", sa.Unicode(length=255), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=True), sa.Column("value", sa.UnicodeText(), nullable=True),
sa.PrimaryKeyConstraint('id') sa.Column("created_at", sa.DateTime(), nullable=True),
sa.PrimaryKeyConstraint("id"),
) )
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_table('analytics') op.drop_table("analytics")
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -12,31 +12,40 @@ from project import dbtypes
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '50337ecd23db' revision = "50337ecd23db"
down_revision = '6be822396123' down_revision = "6be822396123"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
#op.drop_table('spatial_ref_sys') # op.drop_table('spatial_ref_sys')
op.add_column('eventsuggestion', sa.Column('event_id', sa.Integer(), nullable=True)) op.add_column("eventsuggestion", sa.Column("event_id", sa.Integer(), nullable=True))
op.create_foreign_key(None, 'eventsuggestion', 'event', ['event_id'], ['id']) op.create_foreign_key(None, "eventsuggestion", "event", ["event_id"], ["id"])
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'eventsuggestion', type_='foreignkey') op.drop_constraint(None, "eventsuggestion", type_="foreignkey")
op.drop_column('eventsuggestion', 'event_id') op.drop_column("eventsuggestion", "event_id")
op.create_table('spatial_ref_sys', op.create_table(
sa.Column('srid', sa.INTEGER(), autoincrement=False, nullable=False), "spatial_ref_sys",
sa.Column('auth_name', sa.VARCHAR(length=256), autoincrement=False, nullable=True), sa.Column("srid", sa.INTEGER(), autoincrement=False, nullable=False),
sa.Column('auth_srid', sa.INTEGER(), autoincrement=False, nullable=True), sa.Column(
sa.Column('srtext', sa.VARCHAR(length=2048), autoincrement=False, nullable=True), "auth_name", sa.VARCHAR(length=256), autoincrement=False, nullable=True
sa.Column('proj4text', sa.VARCHAR(length=2048), autoincrement=False, nullable=True), ),
sa.CheckConstraint('(srid > 0) AND (srid <= 998999)', name='spatial_ref_sys_srid_check'), sa.Column("auth_srid", sa.INTEGER(), autoincrement=False, nullable=True),
sa.PrimaryKeyConstraint('srid', name='spatial_ref_sys_pkey') sa.Column(
"srtext", sa.VARCHAR(length=2048), autoincrement=False, nullable=True
),
sa.Column(
"proj4text", sa.VARCHAR(length=2048), autoincrement=False, nullable=True
),
sa.CheckConstraint(
"(srid > 0) AND (srid <= 998999)", name="spatial_ref_sys_srid_check"
),
sa.PrimaryKeyConstraint("srid", name="spatial_ref_sys_pkey"),
) )
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -7,26 +7,26 @@ Create Date: 2020-09-29 15:38:44.033998
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
import sqlalchemy_utils
from project import dbtypes
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '51c47c7f0bdb' revision = "51c47c7f0bdb"
down_revision = '7afc40e11791' down_revision = "7afc40e11791"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.add_column('featuredevent', sa.Column('admin_unit_id', sa.Integer(), nullable=False)) op.add_column(
op.create_foreign_key(None, 'featuredevent', 'adminunit', ['admin_unit_id'], ['id']) "featuredevent", sa.Column("admin_unit_id", sa.Integer(), nullable=False)
)
op.create_foreign_key(None, "featuredevent", "adminunit", ["admin_unit_id"], ["id"])
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'featuredevent', type_='foreignkey') op.drop_constraint(None, "featuredevent", type_="foreignkey")
op.drop_column('featuredevent', 'admin_unit_id') op.drop_column("featuredevent", "admin_unit_id")
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -7,26 +7,26 @@ Create Date: 2020-07-13 19:01:04.770613
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
import sqlalchemy_utils
from project import dbtypes
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '5c8457f2eac1' revision = "5c8457f2eac1"
down_revision = 'ed6bb2084bbd' down_revision = "ed6bb2084bbd"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.add_column('event', sa.Column('end', sa.DateTime(timezone=True), nullable=True)) op.add_column("event", sa.Column("end", sa.DateTime(timezone=True), nullable=True))
op.add_column('event', sa.Column('start', sa.DateTime(timezone=True), nullable=True)) op.add_column(
"event", sa.Column("start", sa.DateTime(timezone=True), nullable=True)
)
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_column('event', 'start') op.drop_column("event", "start")
op.drop_column('event', 'end') op.drop_column("event", "end")
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -12,29 +12,36 @@ from project import dbtypes
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '62e071b0da50' revision = "62e071b0da50"
down_revision = 'dcd0b71650b0' down_revision = "dcd0b71650b0"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.alter_column('eventorganizer', 'name', op.alter_column(
existing_type=sa.VARCHAR(length=255), "eventorganizer", "name", existing_type=sa.VARCHAR(length=255), nullable=False
nullable=False) )
op.create_unique_constraint(None, 'eventorganizer', ['name', 'admin_unit_id']) op.create_unique_constraint(None, "eventorganizer", ["name", "admin_unit_id"])
op.drop_column('eventorganizer', 'org_name') op.drop_column("eventorganizer", "org_name")
op.create_unique_constraint(None, 'eventplace', ['name', 'organizer_id', 'admin_unit_id']) op.create_unique_constraint(
None, "eventplace", ["name", "organizer_id", "admin_unit_id"]
)
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'eventplace', type_='unique') op.drop_constraint(None, "eventplace", type_="unique")
op.add_column('eventorganizer', sa.Column('org_name', sa.VARCHAR(length=255), autoincrement=False, nullable=True)) op.add_column(
op.drop_constraint(None, 'eventorganizer', type_='unique') "eventorganizer",
op.alter_column('eventorganizer', 'name', sa.Column(
existing_type=sa.VARCHAR(length=255), "org_name", sa.VARCHAR(length=255), autoincrement=False, nullable=True
nullable=True) ),
)
op.drop_constraint(None, "eventorganizer", type_="unique")
op.alter_column(
"eventorganizer", "name", existing_type=sa.VARCHAR(length=255), nullable=True
)
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -7,29 +7,40 @@ Create Date: 2020-08-01 15:43:11.377833
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
import sqlalchemy_utils
from project import dbtypes from project import dbtypes
from project.models import EventRejectionReason, EventReviewStatus from project.models import EventRejectionReason, EventReviewStatus
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '67216b6cf293' revision = "67216b6cf293"
down_revision = 'a336ac384c64' down_revision = "a336ac384c64"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.add_column('event', sa.Column('rejection_resaon', dbtypes.IntegerEnum(EventRejectionReason), nullable=True)) op.add_column(
op.add_column('event', sa.Column('review_status', dbtypes.IntegerEnum(EventReviewStatus), nullable=True)) "event",
op.drop_column('event', 'verified') sa.Column(
"rejection_resaon", dbtypes.IntegerEnum(EventRejectionReason), nullable=True
),
)
op.add_column(
"event",
sa.Column(
"review_status", dbtypes.IntegerEnum(EventReviewStatus), nullable=True
),
)
op.drop_column("event", "verified")
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.add_column('event', sa.Column('verified', sa.BOOLEAN(), autoincrement=False, nullable=True)) op.add_column(
op.drop_column('event', 'review_status') "event", sa.Column("verified", sa.BOOLEAN(), autoincrement=False, nullable=True)
op.drop_column('event', 'rejection_resaon') )
op.drop_column("event", "review_status")
op.drop_column("event", "rejection_resaon")
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -12,31 +12,37 @@ from project import dbtypes
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '699c4f6a7fe8' revision = "699c4f6a7fe8"
down_revision = 'b1c05324cc13' down_revision = "b1c05324cc13"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.add_column('eventorganizer', sa.Column('admin_unit_id', sa.Integer(), nullable=True)) op.add_column(
op.create_foreign_key(None, 'eventorganizer', 'adminunit', ['admin_unit_id'], ['id']) "eventorganizer", sa.Column("admin_unit_id", sa.Integer(), nullable=True)
op.add_column('eventplace', sa.Column('admin_unit_id', sa.Integer(), nullable=True)) )
op.add_column('eventplace', sa.Column('organizer_id', sa.Integer(), nullable=True)) op.create_foreign_key(
op.add_column('eventplace', sa.Column('public', sa.Boolean(), nullable=True)) None, "eventorganizer", "adminunit", ["admin_unit_id"], ["id"]
op.create_foreign_key(None, 'eventplace', 'eventorganizer', ['organizer_id'], ['id']) )
op.create_foreign_key(None, 'eventplace', 'adminunit', ['admin_unit_id'], ['id']) op.add_column("eventplace", sa.Column("admin_unit_id", sa.Integer(), nullable=True))
op.add_column("eventplace", sa.Column("organizer_id", sa.Integer(), nullable=True))
op.add_column("eventplace", sa.Column("public", sa.Boolean(), nullable=True))
op.create_foreign_key(
None, "eventplace", "eventorganizer", ["organizer_id"], ["id"]
)
op.create_foreign_key(None, "eventplace", "adminunit", ["admin_unit_id"], ["id"])
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'eventplace', type_='foreignkey') op.drop_constraint(None, "eventplace", type_="foreignkey")
op.drop_constraint(None, 'eventplace', type_='foreignkey') op.drop_constraint(None, "eventplace", type_="foreignkey")
op.drop_column('eventplace', 'public') op.drop_column("eventplace", "public")
op.drop_column('eventplace', 'organizer_id') op.drop_column("eventplace", "organizer_id")
op.drop_column('eventplace', 'admin_unit_id') op.drop_column("eventplace", "admin_unit_id")
op.drop_constraint(None, 'eventorganizer', type_='foreignkey') op.drop_constraint(None, "eventorganizer", type_="foreignkey")
op.drop_column('eventorganizer', 'admin_unit_id') op.drop_column("eventorganizer", "admin_unit_id")
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -12,169 +12,321 @@ from project import dbtypes
from sqlalchemy.dialects import postgresql from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '6b7016f73688' revision = "6b7016f73688"
down_revision = 'a75bd9c8ad3a' down_revision = "a75bd9c8ad3a"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint('event_place_id_fkey', 'event', type_='foreignkey') op.drop_constraint("event_place_id_fkey", "event", type_="foreignkey")
op.drop_constraint('event_host_id_fkey', 'event', type_='foreignkey') op.drop_constraint("event_host_id_fkey", "event", type_="foreignkey")
op.drop_column('event', 'host_id') op.drop_column("event", "host_id")
op.drop_column('event', 'place_id') op.drop_column("event", "place_id")
op.drop_table('eventsuggestiondate') op.drop_table("eventsuggestiondate")
op.drop_table('place') op.drop_table("place")
op.drop_table('org_or_adminunit') op.drop_table("org_or_adminunit")
op.drop_table('actor') op.drop_table("actor")
op.drop_table('adminunitorgroles_organizations') op.drop_table("adminunitorgroles_organizations")
op.drop_table('adminunitorgrole') op.drop_table("adminunitorgrole")
op.drop_table('adminunitorg') op.drop_table("adminunitorg")
op.drop_table('orgmemberroles_members') op.drop_table("orgmemberroles_members")
op.drop_table('orgmember') op.drop_table("orgmember")
op.drop_table('organization') op.drop_table("organization")
op.drop_table('eventsuggestion') op.drop_table("eventsuggestion")
op.drop_table('orgmemberrole') op.drop_table("orgmemberrole")
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.add_column('event', sa.Column('place_id', sa.INTEGER(), autoincrement=False, nullable=True)) op.add_column(
op.add_column('event', sa.Column('host_id', sa.INTEGER(), autoincrement=False, nullable=True)) "event", sa.Column("place_id", sa.INTEGER(), autoincrement=False, nullable=True)
op.create_foreign_key('event_host_id_fkey', 'event', 'org_or_adminunit', ['host_id'], ['id'])
op.create_foreign_key('event_place_id_fkey', 'event', 'place', ['place_id'], ['id'])
op.create_table('orgmemberroles_members',
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
sa.Column('member_id', sa.INTEGER(), autoincrement=False, nullable=True),
sa.Column('role_id', sa.INTEGER(), autoincrement=False, nullable=True),
sa.ForeignKeyConstraint(['member_id'], ['orgmember.id'], name='orgmemberroles_members_member_id_fkey'),
sa.ForeignKeyConstraint(['role_id'], ['orgmemberrole.id'], name='orgmemberroles_members_role_id_fkey'),
sa.PrimaryKeyConstraint('id', name='orgmemberroles_members_pkey')
) )
op.create_table('orgmemberrole', op.add_column(
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False), "event", sa.Column("host_id", sa.INTEGER(), autoincrement=False, nullable=True)
sa.Column('name', sa.VARCHAR(length=80), autoincrement=False, nullable=True),
sa.Column('description', sa.VARCHAR(length=255), autoincrement=False, nullable=True),
sa.Column('permissions', sa.TEXT(), autoincrement=False, nullable=True),
sa.PrimaryKeyConstraint('id', name='orgmemberrole_pkey'),
sa.UniqueConstraint('name', name='orgmemberrole_name_key')
) )
op.create_table('eventsuggestion', op.create_foreign_key(
sa.Column('created_at', postgresql.TIMESTAMP(), autoincrement=False, nullable=True), "event_host_id_fkey", "event", "org_or_adminunit", ["host_id"], ["id"]
sa.Column('id', sa.INTEGER(), server_default=sa.text("nextval('eventsuggestion_id_seq'::regclass)"), autoincrement=True, nullable=False),
sa.Column('admin_unit_id', sa.INTEGER(), autoincrement=False, nullable=False),
sa.Column('host_name', sa.VARCHAR(length=255), autoincrement=False, nullable=False),
sa.Column('event_name', sa.VARCHAR(length=255), autoincrement=False, nullable=False),
sa.Column('description', sa.TEXT(), autoincrement=False, nullable=False),
sa.Column('place_name', sa.VARCHAR(length=255), autoincrement=False, nullable=False),
sa.Column('place_street', sa.VARCHAR(length=255), autoincrement=False, nullable=True),
sa.Column('place_postalCode', sa.VARCHAR(length=255), autoincrement=False, nullable=False),
sa.Column('place_city', sa.VARCHAR(length=255), autoincrement=False, nullable=False),
sa.Column('contact_name', sa.VARCHAR(length=255), autoincrement=False, nullable=False),
sa.Column('contact_email', sa.VARCHAR(length=255), autoincrement=False, nullable=False),
sa.Column('external_link', sa.VARCHAR(length=255), autoincrement=False, nullable=True),
sa.Column('created_by_id', sa.INTEGER(), autoincrement=False, nullable=True),
sa.ForeignKeyConstraint(['admin_unit_id'], ['adminunit.id'], name='eventsuggestion_admin_unit_id_fkey'),
sa.ForeignKeyConstraint(['created_by_id'], ['user.id'], name='eventsuggestion_created_by_id_fkey'),
sa.PrimaryKeyConstraint('id', name='eventsuggestion_pkey'),
postgresql_ignore_search_path=False
) )
op.create_table('orgmember', op.create_foreign_key("event_place_id_fkey", "event", "place", ["place_id"], ["id"])
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False), op.create_table(
sa.Column('organization_id', sa.INTEGER(), autoincrement=False, nullable=False), "orgmemberroles_members",
sa.Column('user_id', sa.INTEGER(), autoincrement=False, nullable=False), sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False),
sa.ForeignKeyConstraint(['organization_id'], ['organization.id'], name='orgmember_organization_id_fkey'), sa.Column("member_id", sa.INTEGER(), autoincrement=False, nullable=True),
sa.ForeignKeyConstraint(['user_id'], ['user.id'], name='orgmember_user_id_fkey'), sa.Column("role_id", sa.INTEGER(), autoincrement=False, nullable=True),
sa.PrimaryKeyConstraint('id', name='orgmember_pkey') sa.ForeignKeyConstraint(
["member_id"],
["orgmember.id"],
name="orgmemberroles_members_member_id_fkey",
),
sa.ForeignKeyConstraint(
["role_id"],
["orgmemberrole.id"],
name="orgmemberroles_members_role_id_fkey",
),
sa.PrimaryKeyConstraint("id", name="orgmemberroles_members_pkey"),
) )
op.create_table('adminunitorg', op.create_table(
sa.Column('id', sa.INTEGER(), server_default=sa.text("nextval('adminunitorg_id_seq'::regclass)"), autoincrement=True, nullable=False), "orgmemberrole",
sa.Column('admin_unit_id', sa.INTEGER(), autoincrement=False, nullable=False), sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False),
sa.Column('organization_id', sa.INTEGER(), autoincrement=False, nullable=False), sa.Column("name", sa.VARCHAR(length=80), autoincrement=False, nullable=True),
sa.ForeignKeyConstraint(['admin_unit_id'], ['adminunit.id'], name='adminunitorg_admin_unit_id_fkey'), sa.Column(
sa.ForeignKeyConstraint(['organization_id'], ['organization.id'], name='adminunitorg_organization_id_fkey'), "description", sa.VARCHAR(length=255), autoincrement=False, nullable=True
sa.PrimaryKeyConstraint('id', name='adminunitorg_pkey'), ),
postgresql_ignore_search_path=False sa.Column("permissions", sa.TEXT(), autoincrement=False, nullable=True),
sa.PrimaryKeyConstraint("id", name="orgmemberrole_pkey"),
sa.UniqueConstraint("name", name="orgmemberrole_name_key"),
) )
op.create_table('adminunitorgroles_organizations', op.create_table(
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False), "eventsuggestion",
sa.Column('admin_unit_org_id', sa.INTEGER(), autoincrement=False, nullable=True), sa.Column(
sa.Column('role_id', sa.INTEGER(), autoincrement=False, nullable=True), "created_at", postgresql.TIMESTAMP(), autoincrement=False, nullable=True
sa.ForeignKeyConstraint(['admin_unit_org_id'], ['adminunitorg.id'], name='adminunitorgroles_organizations_admin_unit_org_id_fkey'), ),
sa.ForeignKeyConstraint(['role_id'], ['adminunitorgrole.id'], name='adminunitorgroles_organizations_role_id_fkey'), sa.Column(
sa.PrimaryKeyConstraint('id', name='adminunitorgroles_organizations_pkey') "id",
sa.INTEGER(),
server_default=sa.text("nextval('eventsuggestion_id_seq'::regclass)"),
autoincrement=True,
nullable=False,
),
sa.Column("admin_unit_id", sa.INTEGER(), autoincrement=False, nullable=False),
sa.Column(
"host_name", sa.VARCHAR(length=255), autoincrement=False, nullable=False
),
sa.Column(
"event_name", sa.VARCHAR(length=255), autoincrement=False, nullable=False
),
sa.Column("description", sa.TEXT(), autoincrement=False, nullable=False),
sa.Column(
"place_name", sa.VARCHAR(length=255), autoincrement=False, nullable=False
),
sa.Column(
"place_street", sa.VARCHAR(length=255), autoincrement=False, nullable=True
),
sa.Column(
"place_postalCode",
sa.VARCHAR(length=255),
autoincrement=False,
nullable=False,
),
sa.Column(
"place_city", sa.VARCHAR(length=255), autoincrement=False, nullable=False
),
sa.Column(
"contact_name", sa.VARCHAR(length=255), autoincrement=False, nullable=False
),
sa.Column(
"contact_email", sa.VARCHAR(length=255), autoincrement=False, nullable=False
),
sa.Column(
"external_link", sa.VARCHAR(length=255), autoincrement=False, nullable=True
),
sa.Column("created_by_id", sa.INTEGER(), autoincrement=False, nullable=True),
sa.ForeignKeyConstraint(
["admin_unit_id"],
["adminunit.id"],
name="eventsuggestion_admin_unit_id_fkey",
),
sa.ForeignKeyConstraint(
["created_by_id"], ["user.id"], name="eventsuggestion_created_by_id_fkey"
),
sa.PrimaryKeyConstraint("id", name="eventsuggestion_pkey"),
postgresql_ignore_search_path=False,
) )
op.create_table('organization', op.create_table(
sa.Column('created_at', postgresql.TIMESTAMP(), autoincrement=False, nullable=True), "orgmember",
sa.Column('id', sa.INTEGER(), server_default=sa.text("nextval('organization_id_seq'::regclass)"), autoincrement=True, nullable=False), sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False),
sa.Column('name', sa.VARCHAR(length=255), autoincrement=False, nullable=True), sa.Column("organization_id", sa.INTEGER(), autoincrement=False, nullable=False),
sa.Column('legal_name', sa.VARCHAR(length=255), autoincrement=False, nullable=True), sa.Column("user_id", sa.INTEGER(), autoincrement=False, nullable=False),
sa.Column('location_id', sa.INTEGER(), autoincrement=False, nullable=True), sa.ForeignKeyConstraint(
sa.Column('logo_id', sa.INTEGER(), autoincrement=False, nullable=True), ["organization_id"],
sa.Column('url', sa.VARCHAR(length=255), autoincrement=False, nullable=True), ["organization.id"],
sa.Column('created_by_id', sa.INTEGER(), autoincrement=False, nullable=True), name="orgmember_organization_id_fkey",
sa.Column('email', sa.VARCHAR(length=255), autoincrement=False, nullable=True), ),
sa.Column('phone', sa.VARCHAR(length=255), autoincrement=False, nullable=True), sa.ForeignKeyConstraint(
sa.Column('fax', sa.VARCHAR(length=255), autoincrement=False, nullable=True), ["user_id"], ["user.id"], name="orgmember_user_id_fkey"
sa.Column('short_name', sa.VARCHAR(length=100), autoincrement=False, nullable=True), ),
sa.ForeignKeyConstraint(['created_by_id'], ['user.id'], name='organization_created_by_id_fkey'), sa.PrimaryKeyConstraint("id", name="orgmember_pkey"),
sa.ForeignKeyConstraint(['location_id'], ['location.id'], name='organization_location_id_fkey'),
sa.ForeignKeyConstraint(['logo_id'], ['image.id'], name='organization_logo_id_fkey'),
sa.PrimaryKeyConstraint('id', name='organization_pkey'),
sa.UniqueConstraint('name', name='organization_name_key'),
sa.UniqueConstraint('short_name', name='organization_short_name_key'),
postgresql_ignore_search_path=False
) )
op.create_table('adminunitorgrole', op.create_table(
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False), "adminunitorg",
sa.Column('name', sa.VARCHAR(length=80), autoincrement=False, nullable=True), sa.Column(
sa.Column('description', sa.VARCHAR(length=255), autoincrement=False, nullable=True), "id",
sa.Column('permissions', sa.TEXT(), autoincrement=False, nullable=True), sa.INTEGER(),
sa.PrimaryKeyConstraint('id', name='adminunitorgrole_pkey'), server_default=sa.text("nextval('adminunitorg_id_seq'::regclass)"),
sa.UniqueConstraint('name', name='adminunitorgrole_name_key') autoincrement=True,
nullable=False,
),
sa.Column("admin_unit_id", sa.INTEGER(), autoincrement=False, nullable=False),
sa.Column("organization_id", sa.INTEGER(), autoincrement=False, nullable=False),
sa.ForeignKeyConstraint(
["admin_unit_id"], ["adminunit.id"], name="adminunitorg_admin_unit_id_fkey"
),
sa.ForeignKeyConstraint(
["organization_id"],
["organization.id"],
name="adminunitorg_organization_id_fkey",
),
sa.PrimaryKeyConstraint("id", name="adminunitorg_pkey"),
postgresql_ignore_search_path=False,
) )
op.create_table('actor', op.create_table(
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False), "adminunitorgroles_organizations",
sa.Column('user_id', sa.INTEGER(), autoincrement=False, nullable=False), sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False),
sa.Column('organization_id', sa.INTEGER(), autoincrement=False, nullable=True), sa.Column(
sa.Column('admin_unit_id', sa.INTEGER(), autoincrement=False, nullable=True), "admin_unit_org_id", sa.INTEGER(), autoincrement=False, nullable=True
sa.ForeignKeyConstraint(['admin_unit_id'], ['adminunit.id'], name='actor_admin_unit_id_fkey'), ),
sa.ForeignKeyConstraint(['organization_id'], ['organization.id'], name='actor_organization_id_fkey'), sa.Column("role_id", sa.INTEGER(), autoincrement=False, nullable=True),
sa.ForeignKeyConstraint(['user_id'], ['user.id'], name='actor_user_id_fkey'), sa.ForeignKeyConstraint(
sa.PrimaryKeyConstraint('id', name='actor_pkey'), ["admin_unit_org_id"],
sa.UniqueConstraint('user_id', 'organization_id', 'admin_unit_id', name='actor_user_id_organization_id_admin_unit_id_key') ["adminunitorg.id"],
name="adminunitorgroles_organizations_admin_unit_org_id_fkey",
),
sa.ForeignKeyConstraint(
["role_id"],
["adminunitorgrole.id"],
name="adminunitorgroles_organizations_role_id_fkey",
),
sa.PrimaryKeyConstraint("id", name="adminunitorgroles_organizations_pkey"),
) )
op.create_table('org_or_adminunit', op.create_table(
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False), "organization",
sa.Column('organization_id', sa.INTEGER(), autoincrement=False, nullable=True), sa.Column(
sa.Column('admin_unit_id', sa.INTEGER(), autoincrement=False, nullable=True), "created_at", postgresql.TIMESTAMP(), autoincrement=False, nullable=True
sa.CheckConstraint('NOT ((organization_id IS NULL) AND (admin_unit_id IS NULL))', name='org_or_adminunit_check'), ),
sa.ForeignKeyConstraint(['admin_unit_id'], ['adminunit.id'], name='org_or_adminunit_admin_unit_id_fkey'), sa.Column(
sa.ForeignKeyConstraint(['organization_id'], ['organization.id'], name='org_or_adminunit_organization_id_fkey'), "id",
sa.PrimaryKeyConstraint('id', name='org_or_adminunit_pkey'), sa.INTEGER(),
sa.UniqueConstraint('organization_id', 'admin_unit_id', name='org_or_adminunit_organization_id_admin_unit_id_key') server_default=sa.text("nextval('organization_id_seq'::regclass)"),
autoincrement=True,
nullable=False,
),
sa.Column("name", sa.VARCHAR(length=255), autoincrement=False, nullable=True),
sa.Column(
"legal_name", sa.VARCHAR(length=255), autoincrement=False, nullable=True
),
sa.Column("location_id", sa.INTEGER(), autoincrement=False, nullable=True),
sa.Column("logo_id", sa.INTEGER(), autoincrement=False, nullable=True),
sa.Column("url", sa.VARCHAR(length=255), autoincrement=False, nullable=True),
sa.Column("created_by_id", sa.INTEGER(), autoincrement=False, nullable=True),
sa.Column("email", sa.VARCHAR(length=255), autoincrement=False, nullable=True),
sa.Column("phone", sa.VARCHAR(length=255), autoincrement=False, nullable=True),
sa.Column("fax", sa.VARCHAR(length=255), autoincrement=False, nullable=True),
sa.Column(
"short_name", sa.VARCHAR(length=100), autoincrement=False, nullable=True
),
sa.ForeignKeyConstraint(
["created_by_id"], ["user.id"], name="organization_created_by_id_fkey"
),
sa.ForeignKeyConstraint(
["location_id"], ["location.id"], name="organization_location_id_fkey"
),
sa.ForeignKeyConstraint(
["logo_id"], ["image.id"], name="organization_logo_id_fkey"
),
sa.PrimaryKeyConstraint("id", name="organization_pkey"),
sa.UniqueConstraint("name", name="organization_name_key"),
sa.UniqueConstraint("short_name", name="organization_short_name_key"),
postgresql_ignore_search_path=False,
) )
op.create_table('place', op.create_table(
sa.Column('created_at', postgresql.TIMESTAMP(), autoincrement=False, nullable=True), "adminunitorgrole",
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False), sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False),
sa.Column('name', sa.VARCHAR(length=255), autoincrement=False, nullable=False), sa.Column("name", sa.VARCHAR(length=80), autoincrement=False, nullable=True),
sa.Column('location_id', sa.INTEGER(), autoincrement=False, nullable=True), sa.Column(
sa.Column('photo_id', sa.INTEGER(), autoincrement=False, nullable=True), "description", sa.VARCHAR(length=255), autoincrement=False, nullable=True
sa.Column('url', sa.VARCHAR(length=255), autoincrement=False, nullable=True), ),
sa.Column('description', sa.TEXT(), autoincrement=False, nullable=True), sa.Column("permissions", sa.TEXT(), autoincrement=False, nullable=True),
sa.Column('created_by_id', sa.INTEGER(), autoincrement=False, nullable=True), sa.PrimaryKeyConstraint("id", name="adminunitorgrole_pkey"),
sa.ForeignKeyConstraint(['created_by_id'], ['user.id'], name='place_created_by_id_fkey'), sa.UniqueConstraint("name", name="adminunitorgrole_name_key"),
sa.ForeignKeyConstraint(['location_id'], ['location.id'], name='place_location_id_fkey'),
sa.ForeignKeyConstraint(['photo_id'], ['image.id'], name='place_photo_id_fkey'),
sa.PrimaryKeyConstraint('id', name='place_pkey')
) )
op.create_table('eventsuggestiondate', op.create_table(
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False), "actor",
sa.Column('event_suggestion_id', sa.INTEGER(), autoincrement=False, nullable=False), sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False),
sa.Column('start', postgresql.TIMESTAMP(timezone=True), autoincrement=False, nullable=False), sa.Column("user_id", sa.INTEGER(), autoincrement=False, nullable=False),
sa.ForeignKeyConstraint(['event_suggestion_id'], ['eventsuggestion.id'], name='eventsuggestiondate_event_suggestion_id_fkey'), sa.Column("organization_id", sa.INTEGER(), autoincrement=False, nullable=True),
sa.PrimaryKeyConstraint('id', name='eventsuggestiondate_pkey') sa.Column("admin_unit_id", sa.INTEGER(), autoincrement=False, nullable=True),
sa.ForeignKeyConstraint(
["admin_unit_id"], ["adminunit.id"], name="actor_admin_unit_id_fkey"
),
sa.ForeignKeyConstraint(
["organization_id"], ["organization.id"], name="actor_organization_id_fkey"
),
sa.ForeignKeyConstraint(["user_id"], ["user.id"], name="actor_user_id_fkey"),
sa.PrimaryKeyConstraint("id", name="actor_pkey"),
sa.UniqueConstraint(
"user_id",
"organization_id",
"admin_unit_id",
name="actor_user_id_organization_id_admin_unit_id_key",
),
)
op.create_table(
"org_or_adminunit",
sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False),
sa.Column("organization_id", sa.INTEGER(), autoincrement=False, nullable=True),
sa.Column("admin_unit_id", sa.INTEGER(), autoincrement=False, nullable=True),
sa.CheckConstraint(
"NOT ((organization_id IS NULL) AND (admin_unit_id IS NULL))",
name="org_or_adminunit_check",
),
sa.ForeignKeyConstraint(
["admin_unit_id"],
["adminunit.id"],
name="org_or_adminunit_admin_unit_id_fkey",
),
sa.ForeignKeyConstraint(
["organization_id"],
["organization.id"],
name="org_or_adminunit_organization_id_fkey",
),
sa.PrimaryKeyConstraint("id", name="org_or_adminunit_pkey"),
sa.UniqueConstraint(
"organization_id",
"admin_unit_id",
name="org_or_adminunit_organization_id_admin_unit_id_key",
),
)
op.create_table(
"place",
sa.Column(
"created_at", postgresql.TIMESTAMP(), autoincrement=False, nullable=True
),
sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False),
sa.Column("name", sa.VARCHAR(length=255), autoincrement=False, nullable=False),
sa.Column("location_id", sa.INTEGER(), autoincrement=False, nullable=True),
sa.Column("photo_id", sa.INTEGER(), autoincrement=False, nullable=True),
sa.Column("url", sa.VARCHAR(length=255), autoincrement=False, nullable=True),
sa.Column("description", sa.TEXT(), autoincrement=False, nullable=True),
sa.Column("created_by_id", sa.INTEGER(), autoincrement=False, nullable=True),
sa.ForeignKeyConstraint(
["created_by_id"], ["user.id"], name="place_created_by_id_fkey"
),
sa.ForeignKeyConstraint(
["location_id"], ["location.id"], name="place_location_id_fkey"
),
sa.ForeignKeyConstraint(["photo_id"], ["image.id"], name="place_photo_id_fkey"),
sa.PrimaryKeyConstraint("id", name="place_pkey"),
)
op.create_table(
"eventsuggestiondate",
sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False),
sa.Column(
"event_suggestion_id", sa.INTEGER(), autoincrement=False, nullable=False
),
sa.Column(
"start",
postgresql.TIMESTAMP(timezone=True),
autoincrement=False,
nullable=False,
),
sa.ForeignKeyConstraint(
["event_suggestion_id"],
["eventsuggestion.id"],
name="eventsuggestiondate_event_suggestion_id_fkey",
),
sa.PrimaryKeyConstraint("id", name="eventsuggestiondate_pkey"),
) )
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -12,37 +12,54 @@ from project import dbtypes
from sqlalchemy.dialects import postgresql from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '6be822396123' revision = "6be822396123"
down_revision = '021f602d9965' down_revision = "021f602d9965"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
#op.drop_table('spatial_ref_sys') # op.drop_table('spatial_ref_sys')
op.drop_table('eventcontact') op.drop_table("eventcontact")
op.add_column('eventsuggestion', sa.Column('contact_email_notice', sa.Boolean(), nullable=True)) op.add_column(
"eventsuggestion",
sa.Column("contact_email_notice", sa.Boolean(), nullable=True),
)
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_column('eventsuggestion', 'contact_email_notice') op.drop_column("eventsuggestion", "contact_email_notice")
op.create_table('eventcontact', op.create_table(
sa.Column('created_at', postgresql.TIMESTAMP(), autoincrement=False, nullable=True), "eventcontact",
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False), sa.Column(
sa.Column('created_by_id', sa.INTEGER(), autoincrement=False, nullable=True), "created_at", postgresql.TIMESTAMP(), autoincrement=False, nullable=True
sa.ForeignKeyConstraint(['created_by_id'], ['user.id'], name='eventcontact_created_by_id_fkey'), ),
sa.PrimaryKeyConstraint('id', name='eventcontact_pkey') sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False),
sa.Column("created_by_id", sa.INTEGER(), autoincrement=False, nullable=True),
sa.ForeignKeyConstraint(
["created_by_id"], ["user.id"], name="eventcontact_created_by_id_fkey"
),
sa.PrimaryKeyConstraint("id", name="eventcontact_pkey"),
) )
op.create_table('spatial_ref_sys', op.create_table(
sa.Column('srid', sa.INTEGER(), autoincrement=False, nullable=False), "spatial_ref_sys",
sa.Column('auth_name', sa.VARCHAR(length=256), autoincrement=False, nullable=True), sa.Column("srid", sa.INTEGER(), autoincrement=False, nullable=False),
sa.Column('auth_srid', sa.INTEGER(), autoincrement=False, nullable=True), sa.Column(
sa.Column('srtext', sa.VARCHAR(length=2048), autoincrement=False, nullable=True), "auth_name", sa.VARCHAR(length=256), autoincrement=False, nullable=True
sa.Column('proj4text', sa.VARCHAR(length=2048), autoincrement=False, nullable=True), ),
sa.CheckConstraint('(srid > 0) AND (srid <= 998999)', name='spatial_ref_sys_srid_check'), sa.Column("auth_srid", sa.INTEGER(), autoincrement=False, nullable=True),
sa.PrimaryKeyConstraint('srid', name='spatial_ref_sys_pkey') sa.Column(
"srtext", sa.VARCHAR(length=2048), autoincrement=False, nullable=True
),
sa.Column(
"proj4text", sa.VARCHAR(length=2048), autoincrement=False, nullable=True
),
sa.CheckConstraint(
"(srid > 0) AND (srid <= 998999)", name="spatial_ref_sys_srid_check"
),
sa.PrimaryKeyConstraint("srid", name="spatial_ref_sys_pkey"),
) )
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -11,35 +11,43 @@ import sqlalchemy_utils
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '75c07cb9cfe3' revision = "75c07cb9cfe3"
down_revision = 'abf0f671ba27' down_revision = "abf0f671ba27"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.add_column('adminunit', sa.Column('email', sa.Unicode(length=255), nullable=True)) op.add_column(
op.add_column('adminunit', sa.Column('location_id', sa.Integer(), nullable=True)) "adminunit", sa.Column("email", sa.Unicode(length=255), nullable=True)
op.add_column('adminunit', sa.Column('logo_id', sa.Integer(), nullable=True)) )
op.add_column('adminunit', sa.Column('phone', sa.Unicode(length=255), nullable=True)) op.add_column("adminunit", sa.Column("location_id", sa.Integer(), nullable=True))
op.add_column('adminunit', sa.Column('url', sa.String(length=255), nullable=True)) op.add_column("adminunit", sa.Column("logo_id", sa.Integer(), nullable=True))
op.create_foreign_key(None, 'adminunit', 'image', ['logo_id'], ['id']) op.add_column(
op.create_foreign_key(None, 'adminunit', 'location', ['location_id'], ['id']) "adminunit", sa.Column("phone", sa.Unicode(length=255), nullable=True)
op.add_column('organization', sa.Column('email', sa.Unicode(length=255), nullable=True)) )
op.add_column('organization', sa.Column('phone', sa.Unicode(length=255), nullable=True)) op.add_column("adminunit", sa.Column("url", sa.String(length=255), nullable=True))
op.create_foreign_key(None, "adminunit", "image", ["logo_id"], ["id"])
op.create_foreign_key(None, "adminunit", "location", ["location_id"], ["id"])
op.add_column(
"organization", sa.Column("email", sa.Unicode(length=255), nullable=True)
)
op.add_column(
"organization", sa.Column("phone", sa.Unicode(length=255), nullable=True)
)
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_column('organization', 'phone') op.drop_column("organization", "phone")
op.drop_column('organization', 'email') op.drop_column("organization", "email")
op.drop_constraint(None, 'adminunit', type_='foreignkey') op.drop_constraint(None, "adminunit", type_="foreignkey")
op.drop_constraint(None, 'adminunit', type_='foreignkey') op.drop_constraint(None, "adminunit", type_="foreignkey")
op.drop_column('adminunit', 'url') op.drop_column("adminunit", "url")
op.drop_column('adminunit', 'phone') op.drop_column("adminunit", "phone")
op.drop_column('adminunit', 'logo_id') op.drop_column("adminunit", "logo_id")
op.drop_column('adminunit', 'location_id') op.drop_column("adminunit", "location_id")
op.drop_column('adminunit', 'email') op.drop_column("adminunit", "email")
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -7,38 +7,52 @@ Create Date: 2020-09-28 10:38:46.424791
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
import sqlalchemy_utils
from project import dbtypes from project import dbtypes
from project.models import FeaturedEventRejectionReason, FeaturedEventReviewStatus from project.models import FeaturedEventRejectionReason, FeaturedEventReviewStatus
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '7afc40e11791' revision = "7afc40e11791"
down_revision = 'a8c662c46047' down_revision = "a8c662c46047"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.create_table('featuredevent', op.create_table(
sa.Column('created_at', sa.DateTime(), nullable=True), "featuredevent",
sa.Column('id', sa.Integer(), nullable=False), sa.Column("created_at", sa.DateTime(), nullable=True),
sa.Column('event_id', sa.Integer(), nullable=False), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('review_status', dbtypes.IntegerEnum(FeaturedEventReviewStatus), nullable=True), sa.Column("event_id", sa.Integer(), nullable=False),
sa.Column('rejection_resaon', dbtypes.IntegerEnum(FeaturedEventRejectionReason), nullable=True), sa.Column(
sa.Column('rating', sa.Integer(), nullable=True), "review_status",
sa.Column('created_by_id', sa.Integer(), nullable=True), dbtypes.IntegerEnum(FeaturedEventReviewStatus),
sa.ForeignKeyConstraint(['created_by_id'], ['user.id'], ), nullable=True,
sa.ForeignKeyConstraint(['event_id'], ['event.id'], ), ),
sa.PrimaryKeyConstraint('id') sa.Column(
"rejection_resaon",
dbtypes.IntegerEnum(FeaturedEventRejectionReason),
nullable=True,
),
sa.Column("rating", sa.Integer(), nullable=True),
sa.Column("created_by_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(
["created_by_id"],
["user.id"],
),
sa.ForeignKeyConstraint(
["event_id"],
["event.id"],
),
sa.PrimaryKeyConstraint("id"),
) )
op.add_column('event', sa.Column('rating', sa.Integer(), nullable=True)) op.add_column("event", sa.Column("rating", sa.Integer(), nullable=True))
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_column('event', 'rating') op.drop_column("event", "rating")
op.drop_table('featuredevent') op.drop_table("featuredevent")
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -12,27 +12,31 @@ from project import dbtypes
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '8f4df40a36f3' revision = "8f4df40a36f3"
down_revision = 'f71c86333bfb' down_revision = "f71c86333bfb"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.create_table('adminunitmemberinvitation', op.create_table(
sa.Column('id', sa.Integer(), nullable=False), "adminunitmemberinvitation",
sa.Column('admin_unit_id', sa.Integer(), nullable=False), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('email', sa.String(length=255), nullable=True), sa.Column("admin_unit_id", sa.Integer(), nullable=False),
sa.Column('roles', sa.UnicodeText(), nullable=True), sa.Column("email", sa.String(length=255), nullable=True),
sa.ForeignKeyConstraint(['admin_unit_id'], ['adminunit.id'], ), sa.Column("roles", sa.UnicodeText(), nullable=True),
sa.PrimaryKeyConstraint('id'), sa.ForeignKeyConstraint(
sa.UniqueConstraint('email', 'admin_unit_id') ["admin_unit_id"],
["adminunit.id"],
),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("email", "admin_unit_id"),
) )
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_table('adminunitmemberinvitation') op.drop_table("adminunitmemberinvitation")
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -7,41 +7,65 @@ Create Date: 2020-10-18 13:06:47.639083
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
import sqlalchemy_utils
from project import dbtypes
from project.models import EventRejectionReason, EventReviewStatus
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '92f37474ad62' revision = "92f37474ad62"
down_revision = '0a282a331e35' down_revision = "0a282a331e35"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
#op.drop_table('spatial_ref_sys') # op.drop_table('spatial_ref_sys')
op.drop_constraint('eventplace_name_organizer_id_admin_unit_id_key', 'eventplace', type_='unique') op.drop_constraint(
op.drop_constraint('eventplace_organizer_id_fkey', 'eventplace', type_='foreignkey') "eventplace_name_organizer_id_admin_unit_id_key", "eventplace", type_="unique"
op.drop_column('eventplace', 'public') )
op.drop_column('eventplace', 'organizer_id') op.drop_constraint("eventplace_organizer_id_fkey", "eventplace", type_="foreignkey")
op.drop_column("eventplace", "public")
op.drop_column("eventplace", "organizer_id")
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.add_column('eventplace', sa.Column('organizer_id', sa.INTEGER(), autoincrement=False, nullable=True)) op.add_column(
op.add_column('eventplace', sa.Column('public', sa.BOOLEAN(), autoincrement=False, nullable=True)) "eventplace",
op.create_foreign_key('eventplace_organizer_id_fkey', 'eventplace', 'eventorganizer', ['organizer_id'], ['id']) sa.Column("organizer_id", sa.INTEGER(), autoincrement=False, nullable=True),
op.create_unique_constraint('eventplace_name_organizer_id_admin_unit_id_key', 'eventplace', ['name', 'organizer_id', 'admin_unit_id']) )
op.create_table('spatial_ref_sys', op.add_column(
sa.Column('srid', sa.INTEGER(), autoincrement=False, nullable=False), "eventplace",
sa.Column('auth_name', sa.VARCHAR(length=256), autoincrement=False, nullable=True), sa.Column("public", sa.BOOLEAN(), autoincrement=False, nullable=True),
sa.Column('auth_srid', sa.INTEGER(), autoincrement=False, nullable=True), )
sa.Column('srtext', sa.VARCHAR(length=2048), autoincrement=False, nullable=True), op.create_foreign_key(
sa.Column('proj4text', sa.VARCHAR(length=2048), autoincrement=False, nullable=True), "eventplace_organizer_id_fkey",
sa.CheckConstraint('(srid > 0) AND (srid <= 998999)', name='spatial_ref_sys_srid_check'), "eventplace",
sa.PrimaryKeyConstraint('srid', name='spatial_ref_sys_pkey') "eventorganizer",
["organizer_id"],
["id"],
)
op.create_unique_constraint(
"eventplace_name_organizer_id_admin_unit_id_key",
"eventplace",
["name", "organizer_id", "admin_unit_id"],
)
op.create_table(
"spatial_ref_sys",
sa.Column("srid", sa.INTEGER(), autoincrement=False, nullable=False),
sa.Column(
"auth_name", sa.VARCHAR(length=256), autoincrement=False, nullable=True
),
sa.Column("auth_srid", sa.INTEGER(), autoincrement=False, nullable=True),
sa.Column(
"srtext", sa.VARCHAR(length=2048), autoincrement=False, nullable=True
),
sa.Column(
"proj4text", sa.VARCHAR(length=2048), autoincrement=False, nullable=True
),
sa.CheckConstraint(
"(srid > 0) AND (srid <= 998999)", name="spatial_ref_sys_srid_check"
),
sa.PrimaryKeyConstraint("srid", name="spatial_ref_sys_pkey"),
) )
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -12,48 +12,44 @@ from project import dbtypes
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '975c22ae802b' revision = "975c22ae802b"
down_revision = '5c8457f2eac1' down_revision = "5c8457f2eac1"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.create_table('eventorganizer', op.create_table(
sa.Column('created_at', sa.DateTime(), nullable=True), "eventorganizer",
sa.Column('id', sa.Integer(), nullable=False), sa.Column("created_at", sa.DateTime(), nullable=True),
sa.Column('name', sa.Unicode(length=255), nullable=True), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('org_name', sa.Unicode(length=255), nullable=True), sa.Column("name", sa.Unicode(length=255), nullable=True),
sa.Column('url', sa.String(length=255), nullable=True), sa.Column("org_name", sa.Unicode(length=255), nullable=True),
sa.Column('email', sa.Unicode(length=255), nullable=True), sa.Column("url", sa.String(length=255), nullable=True),
sa.Column('phone', sa.Unicode(length=255), nullable=True), sa.Column("email", sa.Unicode(length=255), nullable=True),
sa.Column('created_by_id', sa.Integer(), nullable=True), sa.Column("phone", sa.Unicode(length=255), nullable=True),
sa.ForeignKeyConstraint(['created_by_id'], ['user.id'], ), sa.Column("created_by_id", sa.Integer(), nullable=True),
sa.PrimaryKeyConstraint('id') sa.ForeignKeyConstraint(
["created_by_id"],
["user.id"],
),
sa.PrimaryKeyConstraint("id"),
) )
op.add_column('event', sa.Column('organizer_id', sa.Integer(), nullable=True)) op.add_column("event", sa.Column("organizer_id", sa.Integer(), nullable=True))
op.alter_column('event', 'host_id', op.alter_column("event", "host_id", existing_type=sa.INTEGER(), nullable=True)
existing_type=sa.INTEGER(), op.alter_column("event", "place_id", existing_type=sa.INTEGER(), nullable=True)
nullable=True) op.create_foreign_key(None, "event", "eventorganizer", ["organizer_id"], ["id"])
op.alter_column('event', 'place_id', op.drop_constraint("place_name_key", "place", type_="unique")
existing_type=sa.INTEGER(),
nullable=True)
op.create_foreign_key(None, 'event', 'eventorganizer', ['organizer_id'], ['id'])
op.drop_constraint('place_name_key', 'place', type_='unique')
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.create_unique_constraint('place_name_key', 'place', ['name']) op.create_unique_constraint("place_name_key", "place", ["name"])
op.drop_constraint(None, 'event', type_='foreignkey') op.drop_constraint(None, "event", type_="foreignkey")
op.alter_column('event', 'place_id', op.alter_column("event", "place_id", existing_type=sa.INTEGER(), nullable=False)
existing_type=sa.INTEGER(), op.alter_column("event", "host_id", existing_type=sa.INTEGER(), nullable=False)
nullable=False) op.drop_column("event", "organizer_id")
op.alter_column('event', 'host_id', op.drop_table("eventorganizer")
existing_type=sa.INTEGER(),
nullable=False)
op.drop_column('event', 'organizer_id')
op.drop_table('eventorganizer')
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -12,32 +12,36 @@ from project import dbtypes
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = 'a336ac384c64' revision = "a336ac384c64"
down_revision = '62e071b0da50' down_revision = "62e071b0da50"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.create_table('eventcontact', op.create_table(
sa.Column('created_at', sa.DateTime(), nullable=True), "eventcontact",
sa.Column('id', sa.Integer(), nullable=False), sa.Column("created_at", sa.DateTime(), nullable=True),
sa.Column('name', sa.Unicode(length=255), nullable=False), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('email', sa.Unicode(length=255), nullable=True), sa.Column("name", sa.Unicode(length=255), nullable=False),
sa.Column('phone', sa.Unicode(length=255), nullable=True), sa.Column("email", sa.Unicode(length=255), nullable=True),
sa.Column('created_by_id', sa.Integer(), nullable=True), sa.Column("phone", sa.Unicode(length=255), nullable=True),
sa.ForeignKeyConstraint(['created_by_id'], ['user.id'], ), sa.Column("created_by_id", sa.Integer(), nullable=True),
sa.PrimaryKeyConstraint('id') sa.ForeignKeyConstraint(
["created_by_id"],
["user.id"],
),
sa.PrimaryKeyConstraint("id"),
) )
op.add_column('event', sa.Column('contact_id', sa.Integer(), nullable=True)) op.add_column("event", sa.Column("contact_id", sa.Integer(), nullable=True))
op.create_foreign_key(None, 'event', 'eventcontact', ['contact_id'], ['id']) op.create_foreign_key(None, "event", "eventcontact", ["contact_id"], ["id"])
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'event', type_='foreignkey') op.drop_constraint(None, "event", type_="foreignkey")
op.drop_column('event', 'contact_id') op.drop_column("event", "contact_id")
op.drop_table('eventcontact') op.drop_table("eventcontact")
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -7,65 +7,104 @@ Create Date: 2020-09-29 16:53:02.520125
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
import sqlalchemy_utils
from project import dbtypes from project import dbtypes
from sqlalchemy.dialects import postgresql from sqlalchemy.dialects import postgresql
from project.models import EventReferenceRequestRejectionReason, EventReferenceRequestReviewStatus from project.models import (
EventReferenceRequestRejectionReason,
EventReferenceRequestReviewStatus,
)
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = 'a75bd9c8ad3a' revision = "a75bd9c8ad3a"
down_revision = '51c47c7f0bdb' down_revision = "51c47c7f0bdb"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.create_table('eventreference', op.create_table(
sa.Column('created_at', sa.DateTime(), nullable=True), "eventreference",
sa.Column('id', sa.Integer(), nullable=False), sa.Column("created_at", sa.DateTime(), nullable=True),
sa.Column('event_id', sa.Integer(), nullable=False), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('admin_unit_id', sa.Integer(), nullable=False), sa.Column("event_id", sa.Integer(), nullable=False),
sa.Column('rating', sa.Integer(), nullable=True), sa.Column("admin_unit_id", sa.Integer(), nullable=False),
sa.Column('created_by_id', sa.Integer(), nullable=True), sa.Column("rating", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['admin_unit_id'], ['adminunit.id'], ), sa.Column("created_by_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['created_by_id'], ['user.id'], ), sa.ForeignKeyConstraint(
sa.ForeignKeyConstraint(['event_id'], ['event.id'], ), ["admin_unit_id"],
sa.PrimaryKeyConstraint('id') ["adminunit.id"],
),
sa.ForeignKeyConstraint(
["created_by_id"],
["user.id"],
),
sa.ForeignKeyConstraint(
["event_id"],
["event.id"],
),
sa.PrimaryKeyConstraint("id"),
) )
op.create_table('eventreferencerequest', op.create_table(
sa.Column('created_at', sa.DateTime(), nullable=True), "eventreferencerequest",
sa.Column('id', sa.Integer(), nullable=False), sa.Column("created_at", sa.DateTime(), nullable=True),
sa.Column('event_id', sa.Integer(), nullable=False), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('admin_unit_id', sa.Integer(), nullable=False), sa.Column("event_id", sa.Integer(), nullable=False),
sa.Column('review_status', dbtypes.IntegerEnum(EventReferenceRequestReviewStatus), nullable=True), sa.Column("admin_unit_id", sa.Integer(), nullable=False),
sa.Column('rejection_reason', dbtypes.IntegerEnum(EventReferenceRequestRejectionReason), nullable=True), sa.Column(
sa.Column('created_by_id', sa.Integer(), nullable=True), "review_status",
sa.ForeignKeyConstraint(['admin_unit_id'], ['adminunit.id'], ), dbtypes.IntegerEnum(EventReferenceRequestReviewStatus),
sa.ForeignKeyConstraint(['created_by_id'], ['user.id'], ), nullable=True,
sa.ForeignKeyConstraint(['event_id'], ['event.id'], ), ),
sa.PrimaryKeyConstraint('id') sa.Column(
"rejection_reason",
dbtypes.IntegerEnum(EventReferenceRequestRejectionReason),
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(
["event_id"],
["event.id"],
),
sa.PrimaryKeyConstraint("id"),
) )
op.drop_table('featuredevent') op.drop_table("featuredevent")
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.create_table('featuredevent', op.create_table(
sa.Column('created_at', postgresql.TIMESTAMP(), autoincrement=False, nullable=True), "featuredevent",
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False), sa.Column(
sa.Column('event_id', sa.INTEGER(), autoincrement=False, nullable=False), "created_at", postgresql.TIMESTAMP(), autoincrement=False, nullable=True
sa.Column('review_status', sa.INTEGER(), autoincrement=False, nullable=True), ),
sa.Column('rejection_resaon', sa.INTEGER(), autoincrement=False, nullable=True), sa.Column("id", sa.INTEGER(), autoincrement=True, nullable=False),
sa.Column('rating', sa.INTEGER(), autoincrement=False, nullable=True), sa.Column("event_id", sa.INTEGER(), autoincrement=False, nullable=False),
sa.Column('created_by_id', sa.INTEGER(), autoincrement=False, nullable=True), sa.Column("review_status", sa.INTEGER(), autoincrement=False, nullable=True),
sa.Column('admin_unit_id', sa.INTEGER(), autoincrement=False, nullable=False), sa.Column("rejection_resaon", sa.INTEGER(), autoincrement=False, nullable=True),
sa.ForeignKeyConstraint(['admin_unit_id'], ['adminunit.id'], name='featuredevent_admin_unit_id_fkey'), sa.Column("rating", sa.INTEGER(), autoincrement=False, nullable=True),
sa.ForeignKeyConstraint(['created_by_id'], ['user.id'], name='featuredevent_created_by_id_fkey'), sa.Column("created_by_id", sa.INTEGER(), autoincrement=False, nullable=True),
sa.ForeignKeyConstraint(['event_id'], ['event.id'], name='featuredevent_event_id_fkey'), sa.Column("admin_unit_id", sa.INTEGER(), autoincrement=False, nullable=False),
sa.PrimaryKeyConstraint('id', name='featuredevent_pkey') sa.ForeignKeyConstraint(
["admin_unit_id"], ["adminunit.id"], name="featuredevent_admin_unit_id_fkey"
),
sa.ForeignKeyConstraint(
["created_by_id"], ["user.id"], name="featuredevent_created_by_id_fkey"
),
sa.ForeignKeyConstraint(
["event_id"], ["event.id"], name="featuredevent_event_id_fkey"
),
sa.PrimaryKeyConstraint("id", name="featuredevent_pkey"),
) )
op.drop_table('eventreferencerequest') op.drop_table("eventreferencerequest")
op.drop_table('eventreference') op.drop_table("eventreference")
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -12,21 +12,23 @@ from project import dbtypes
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = 'a8c662c46047' revision = "a8c662c46047"
down_revision = '8f4df40a36f3' down_revision = "8f4df40a36f3"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.add_column('adminunitmemberrole', sa.Column('title', sa.Unicode(length=255), nullable=True)) op.add_column(
op.add_column('role', sa.Column('title', sa.Unicode(length=255), nullable=True)) "adminunitmemberrole", sa.Column("title", sa.Unicode(length=255), nullable=True)
)
op.add_column("role", sa.Column("title", sa.Unicode(length=255), nullable=True))
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_column('role', 'title') op.drop_column("role", "title")
op.drop_column('adminunitmemberrole', 'title') op.drop_column("adminunitmemberrole", "title")
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -11,29 +11,33 @@ import sqlalchemy_utils
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = 'abf0f671ba27' revision = "abf0f671ba27"
down_revision = 'bbad7e33a780' down_revision = "bbad7e33a780"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.create_table('flask_dance_oauth', op.create_table(
sa.Column('id', sa.Integer(), nullable=False), "flask_dance_oauth",
sa.Column('provider', sa.String(length=50), nullable=False), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('created_at', sa.DateTime(), nullable=False), sa.Column("provider", sa.String(length=50), nullable=False),
sa.Column('token', sqlalchemy_utils.types.json.JSONType(), nullable=False), sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column('provider_user_id', sa.String(length=256), nullable=False), sa.Column("token", sqlalchemy_utils.types.json.JSONType(), nullable=False),
sa.Column('user_id', sa.Integer(), nullable=False), sa.Column("provider_user_id", sa.String(length=256), nullable=False),
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ), sa.Column("user_id", sa.Integer(), nullable=False),
sa.PrimaryKeyConstraint('id'), sa.ForeignKeyConstraint(
sa.UniqueConstraint('provider_user_id') ["user_id"],
["user.id"],
),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("provider_user_id"),
) )
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_table('flask_dance_oauth') op.drop_table("flask_dance_oauth")
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -12,23 +12,27 @@ from project import dbtypes
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = 'b128cc637447' revision = "b128cc637447"
down_revision = '41512b20e07c' down_revision = "41512b20e07c"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.add_column('adminunit', sa.Column('fax', sa.Unicode(length=255), nullable=True)) op.add_column("adminunit", sa.Column("fax", sa.Unicode(length=255), nullable=True))
op.add_column('eventorganizer', sa.Column('fax', sa.Unicode(length=255), nullable=True)) op.add_column(
op.add_column('organization', sa.Column('fax', sa.Unicode(length=255), nullable=True)) "eventorganizer", sa.Column("fax", sa.Unicode(length=255), nullable=True)
)
op.add_column(
"organization", sa.Column("fax", sa.Unicode(length=255), nullable=True)
)
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_column('organization', 'fax') op.drop_column("organization", "fax")
op.drop_column('eventorganizer', 'fax') op.drop_column("eventorganizer", "fax")
op.drop_column('adminunit', 'fax') op.drop_column("adminunit", "fax")
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -12,21 +12,21 @@ from project import dbtypes
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = 'b1c05324cc13' revision = "b1c05324cc13"
down_revision = 'cce1284874fa' down_revision = "cce1284874fa"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.create_unique_constraint(None, 'adminunit', ['short_name']) op.create_unique_constraint(None, "adminunit", ["short_name"])
op.create_unique_constraint(None, 'organization', ['short_name']) op.create_unique_constraint(None, "organization", ["short_name"])
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'organization', type_='unique') op.drop_constraint(None, "organization", type_="unique")
op.drop_constraint(None, 'adminunit', type_='unique') op.drop_constraint(None, "adminunit", type_="unique")
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -1,7 +1,7 @@
"""empty message """empty message
Revision ID: bbad7e33a780 Revision ID: bbad7e33a780
Revises: Revises:
Create Date: 2020-06-24 21:17:25.548159 Create Date: 2020-06-24 21:17:25.548159
""" """
@ -10,7 +10,7 @@ import sqlalchemy as sa
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = 'bbad7e33a780' revision = "bbad7e33a780"
down_revision = None down_revision = None
branch_labels = None branch_labels = None
depends_on = None depends_on = None
@ -18,282 +18,420 @@ depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.create_table('adminunitmemberrole', op.create_table(
sa.Column('id', sa.Integer(), nullable=False), "adminunitmemberrole",
sa.Column('name', sa.String(length=80), nullable=True), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('description', sa.String(length=255), nullable=True), sa.Column("name", sa.String(length=80), nullable=True),
sa.Column('permissions', sa.UnicodeText(), nullable=True), sa.Column("description", sa.String(length=255), nullable=True),
sa.PrimaryKeyConstraint('id'), sa.Column("permissions", sa.UnicodeText(), nullable=True),
sa.UniqueConstraint('name') sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("name"),
) )
op.create_table('adminunitorgrole', op.create_table(
sa.Column('id', sa.Integer(), nullable=False), "adminunitorgrole",
sa.Column('name', sa.String(length=80), nullable=True), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('description', sa.String(length=255), nullable=True), sa.Column("name", sa.String(length=80), nullable=True),
sa.Column('permissions', sa.UnicodeText(), nullable=True), sa.Column("description", sa.String(length=255), nullable=True),
sa.PrimaryKeyConstraint('id'), sa.Column("permissions", sa.UnicodeText(), nullable=True),
sa.UniqueConstraint('name') sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("name"),
) )
op.create_table('eventcategory', op.create_table(
sa.Column('id', sa.Integer(), nullable=False), "eventcategory",
sa.Column('name', sa.Unicode(length=255), nullable=False), sa.Column("id", sa.Integer(), nullable=False),
sa.PrimaryKeyConstraint('id'), sa.Column("name", sa.Unicode(length=255), nullable=False),
sa.UniqueConstraint('name') sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("name"),
) )
op.create_table('orgmemberrole', op.create_table(
sa.Column('id', sa.Integer(), nullable=False), "orgmemberrole",
sa.Column('name', sa.String(length=80), nullable=True), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('description', sa.String(length=255), nullable=True), sa.Column("name", sa.String(length=80), nullable=True),
sa.Column('permissions', sa.UnicodeText(), nullable=True), sa.Column("description", sa.String(length=255), nullable=True),
sa.PrimaryKeyConstraint('id'), sa.Column("permissions", sa.UnicodeText(), nullable=True),
sa.UniqueConstraint('name') sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("name"),
) )
op.create_table('role', op.create_table(
sa.Column('id', sa.Integer(), nullable=False), "role",
sa.Column('name', sa.String(length=80), nullable=True), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('description', sa.String(length=255), nullable=True), sa.Column("name", sa.String(length=80), nullable=True),
sa.Column('permissions', sa.UnicodeText(), nullable=True), sa.Column("description", sa.String(length=255), nullable=True),
sa.PrimaryKeyConstraint('id'), sa.Column("permissions", sa.UnicodeText(), nullable=True),
sa.UniqueConstraint('name') sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("name"),
) )
op.create_table('user', op.create_table(
sa.Column('id', sa.Integer(), nullable=False), "user",
sa.Column('email', sa.String(length=255), nullable=True), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('username', sa.String(length=255), nullable=True), sa.Column("email", sa.String(length=255), nullable=True),
sa.Column('password', sa.String(length=255), nullable=True), sa.Column("username", sa.String(length=255), nullable=True),
sa.Column('last_login_at', sa.DateTime(), nullable=True), sa.Column("password", sa.String(length=255), nullable=True),
sa.Column('current_login_at', sa.DateTime(), nullable=True), sa.Column("last_login_at", sa.DateTime(), nullable=True),
sa.Column('last_login_ip', sa.String(length=100), nullable=True), sa.Column("current_login_at", sa.DateTime(), nullable=True),
sa.Column('current_login_ip', sa.String(length=100), nullable=True), sa.Column("last_login_ip", sa.String(length=100), nullable=True),
sa.Column('login_count', sa.Integer(), nullable=True), sa.Column("current_login_ip", sa.String(length=100), nullable=True),
sa.Column('active', sa.Boolean(), nullable=True), sa.Column("login_count", sa.Integer(), nullable=True),
sa.Column('fs_uniquifier', sa.String(length=255), nullable=True), sa.Column("active", sa.Boolean(), nullable=True),
sa.Column('confirmed_at', sa.DateTime(), nullable=True), sa.Column("fs_uniquifier", sa.String(length=255), nullable=True),
sa.PrimaryKeyConstraint('id'), sa.Column("confirmed_at", sa.DateTime(), nullable=True),
sa.UniqueConstraint('email') sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("email"),
) )
op.create_table('adminunit', op.create_table(
sa.Column('created_at', sa.DateTime(), nullable=True), "adminunit",
sa.Column('id', sa.Integer(), nullable=False), sa.Column("created_at", sa.DateTime(), nullable=True),
sa.Column('name', sa.Unicode(length=255), nullable=True), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('created_by_id', sa.Integer(), nullable=True), sa.Column("name", sa.Unicode(length=255), nullable=True),
sa.ForeignKeyConstraint(['created_by_id'], ['user.id'], ), sa.Column("created_by_id", sa.Integer(), nullable=True),
sa.PrimaryKeyConstraint('id'), sa.ForeignKeyConstraint(
sa.UniqueConstraint('name') ["created_by_id"],
["user.id"],
),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("name"),
) )
op.create_table('image', op.create_table(
sa.Column('created_at', sa.DateTime(), nullable=True), "image",
sa.Column('id', sa.Integer(), nullable=False), sa.Column("created_at", sa.DateTime(), nullable=True),
sa.Column('data', sa.LargeBinary(), nullable=True), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('encoding_format', sa.String(length=80), nullable=True), sa.Column("data", sa.LargeBinary(), nullable=True),
sa.Column('created_by_id', sa.Integer(), nullable=True), sa.Column("encoding_format", sa.String(length=80), nullable=True),
sa.ForeignKeyConstraint(['created_by_id'], ['user.id'], ), sa.Column("created_by_id", sa.Integer(), nullable=True),
sa.PrimaryKeyConstraint('id') sa.ForeignKeyConstraint(
["created_by_id"],
["user.id"],
),
sa.PrimaryKeyConstraint("id"),
) )
op.create_table('location', op.create_table(
sa.Column('created_at', sa.DateTime(), nullable=True), "location",
sa.Column('id', sa.Integer(), nullable=False), sa.Column("created_at", sa.DateTime(), nullable=True),
sa.Column('street', sa.Unicode(length=255), nullable=True), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('postalCode', sa.Unicode(length=255), nullable=True), sa.Column("street", sa.Unicode(length=255), nullable=True),
sa.Column('city', sa.Unicode(length=255), nullable=True), sa.Column("postalCode", sa.Unicode(length=255), nullable=True),
sa.Column('state', sa.Unicode(length=255), nullable=True), sa.Column("city", sa.Unicode(length=255), nullable=True),
sa.Column('country', sa.Unicode(length=255), nullable=True), sa.Column("state", sa.Unicode(length=255), nullable=True),
sa.Column('latitude', sa.Numeric(precision=18, scale=16), nullable=True), sa.Column("country", sa.Unicode(length=255), nullable=True),
sa.Column('longitude', sa.Numeric(precision=19, scale=16), nullable=True), sa.Column("latitude", sa.Numeric(precision=18, scale=16), nullable=True),
sa.Column('created_by_id', sa.Integer(), nullable=True), sa.Column("longitude", sa.Numeric(precision=19, scale=16), nullable=True),
sa.ForeignKeyConstraint(['created_by_id'], ['user.id'], ), sa.Column("created_by_id", sa.Integer(), nullable=True),
sa.PrimaryKeyConstraint('id') sa.ForeignKeyConstraint(
["created_by_id"],
["user.id"],
),
sa.PrimaryKeyConstraint("id"),
) )
op.create_table('roles_users', op.create_table(
sa.Column('id', sa.Integer(), nullable=False), "roles_users",
sa.Column('user_id', sa.Integer(), nullable=True), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('role_id', sa.Integer(), nullable=True), sa.Column("user_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['role_id'], ['role.id'], ), sa.Column("role_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ), sa.ForeignKeyConstraint(
sa.PrimaryKeyConstraint('id') ["role_id"],
["role.id"],
),
sa.ForeignKeyConstraint(
["user_id"],
["user.id"],
),
sa.PrimaryKeyConstraint("id"),
) )
op.create_table('adminunitmember', op.create_table(
sa.Column('id', sa.Integer(), nullable=False), "adminunitmember",
sa.Column('admin_unit_id', sa.Integer(), nullable=False), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('user_id', sa.Integer(), nullable=False), sa.Column("admin_unit_id", sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['admin_unit_id'], ['adminunit.id'], ), sa.Column("user_id", sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ), sa.ForeignKeyConstraint(
sa.PrimaryKeyConstraint('id') ["admin_unit_id"],
["adminunit.id"],
),
sa.ForeignKeyConstraint(
["user_id"],
["user.id"],
),
sa.PrimaryKeyConstraint("id"),
) )
op.create_table('eventsuggestion', op.create_table(
sa.Column('created_at', sa.DateTime(), nullable=True), "eventsuggestion",
sa.Column('id', sa.Integer(), nullable=False), sa.Column("created_at", sa.DateTime(), nullable=True),
sa.Column('admin_unit_id', sa.Integer(), nullable=False), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('host_name', sa.Unicode(length=255), nullable=False), sa.Column("admin_unit_id", sa.Integer(), nullable=False),
sa.Column('event_name', sa.Unicode(length=255), nullable=False), sa.Column("host_name", sa.Unicode(length=255), nullable=False),
sa.Column('description', sa.UnicodeText(), nullable=False), sa.Column("event_name", sa.Unicode(length=255), nullable=False),
sa.Column('place_name', sa.Unicode(length=255), nullable=False), sa.Column("description", sa.UnicodeText(), nullable=False),
sa.Column('place_street', sa.Unicode(length=255), nullable=True), sa.Column("place_name", sa.Unicode(length=255), nullable=False),
sa.Column('place_postalCode', sa.Unicode(length=255), nullable=False), sa.Column("place_street", sa.Unicode(length=255), nullable=True),
sa.Column('place_city', sa.Unicode(length=255), nullable=False), sa.Column("place_postalCode", sa.Unicode(length=255), nullable=False),
sa.Column('contact_name', sa.Unicode(length=255), nullable=False), sa.Column("place_city", sa.Unicode(length=255), nullable=False),
sa.Column('contact_email', sa.Unicode(length=255), nullable=False), sa.Column("contact_name", sa.Unicode(length=255), nullable=False),
sa.Column('external_link', sa.String(length=255), nullable=True), sa.Column("contact_email", sa.Unicode(length=255), nullable=False),
sa.Column('created_by_id', sa.Integer(), nullable=True), sa.Column("external_link", sa.String(length=255), nullable=True),
sa.ForeignKeyConstraint(['admin_unit_id'], ['adminunit.id'], ), sa.Column("created_by_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['created_by_id'], ['user.id'], ), sa.ForeignKeyConstraint(
sa.PrimaryKeyConstraint('id') ["admin_unit_id"],
["adminunit.id"],
),
sa.ForeignKeyConstraint(
["created_by_id"],
["user.id"],
),
sa.PrimaryKeyConstraint("id"),
) )
op.create_table('organization', op.create_table(
sa.Column('created_at', sa.DateTime(), nullable=True), "organization",
sa.Column('id', sa.Integer(), nullable=False), sa.Column("created_at", sa.DateTime(), nullable=True),
sa.Column('name', sa.Unicode(length=255), nullable=True), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('legal_name', sa.Unicode(length=255), nullable=True), sa.Column("name", sa.Unicode(length=255), nullable=True),
sa.Column('location_id', sa.Integer(), nullable=True), sa.Column("legal_name", sa.Unicode(length=255), nullable=True),
sa.Column('logo_id', sa.Integer(), nullable=True), sa.Column("location_id", sa.Integer(), nullable=True),
sa.Column('url', sa.String(length=255), nullable=True), sa.Column("logo_id", sa.Integer(), nullable=True),
sa.Column('created_by_id', sa.Integer(), nullable=True), sa.Column("url", sa.String(length=255), nullable=True),
sa.ForeignKeyConstraint(['created_by_id'], ['user.id'], ), sa.Column("created_by_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['location_id'], ['location.id'], ), sa.ForeignKeyConstraint(
sa.ForeignKeyConstraint(['logo_id'], ['image.id'], ), ["created_by_id"],
sa.PrimaryKeyConstraint('id'), ["user.id"],
sa.UniqueConstraint('name') ),
sa.ForeignKeyConstraint(
["location_id"],
["location.id"],
),
sa.ForeignKeyConstraint(
["logo_id"],
["image.id"],
),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("name"),
) )
op.create_table('place', op.create_table(
sa.Column('created_at', sa.DateTime(), nullable=True), "place",
sa.Column('id', sa.Integer(), nullable=False), sa.Column("created_at", sa.DateTime(), nullable=True),
sa.Column('name', sa.Unicode(length=255), nullable=False), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('location_id', sa.Integer(), nullable=True), sa.Column("name", sa.Unicode(length=255), nullable=False),
sa.Column('photo_id', sa.Integer(), nullable=True), sa.Column("location_id", sa.Integer(), nullable=True),
sa.Column('url', sa.String(length=255), nullable=True), sa.Column("photo_id", sa.Integer(), nullable=True),
sa.Column('description', sa.UnicodeText(), nullable=True), sa.Column("url", sa.String(length=255), nullable=True),
sa.Column('created_by_id', sa.Integer(), nullable=True), sa.Column("description", sa.UnicodeText(), nullable=True),
sa.ForeignKeyConstraint(['created_by_id'], ['user.id'], ), sa.Column("created_by_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['location_id'], ['location.id'], ), sa.ForeignKeyConstraint(
sa.ForeignKeyConstraint(['photo_id'], ['image.id'], ), ["created_by_id"],
sa.PrimaryKeyConstraint('id'), ["user.id"],
sa.UniqueConstraint('name') ),
sa.ForeignKeyConstraint(
["location_id"],
["location.id"],
),
sa.ForeignKeyConstraint(
["photo_id"],
["image.id"],
),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("name"),
) )
op.create_table('actor', op.create_table(
sa.Column('id', sa.Integer(), nullable=False), "actor",
sa.Column('user_id', sa.Integer(), nullable=False), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('organization_id', sa.Integer(), nullable=True), sa.Column("user_id", sa.Integer(), nullable=False),
sa.Column('admin_unit_id', sa.Integer(), nullable=True), sa.Column("organization_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['admin_unit_id'], ['adminunit.id'], ), sa.Column("admin_unit_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['organization_id'], ['organization.id'], ), sa.ForeignKeyConstraint(
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ), ["admin_unit_id"],
sa.PrimaryKeyConstraint('id'), ["adminunit.id"],
sa.UniqueConstraint('user_id', 'organization_id', 'admin_unit_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', op.create_table(
sa.Column('id', sa.Integer(), nullable=False), "adminunitmemberroles_members",
sa.Column('member_id', sa.Integer(), nullable=True), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('role_id', sa.Integer(), nullable=True), sa.Column("member_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['member_id'], ['adminunitmember.id'], ), sa.Column("role_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['role_id'], ['adminunitmemberrole.id'], ), sa.ForeignKeyConstraint(
sa.PrimaryKeyConstraint('id') ["member_id"],
["adminunitmember.id"],
),
sa.ForeignKeyConstraint(
["role_id"],
["adminunitmemberrole.id"],
),
sa.PrimaryKeyConstraint("id"),
) )
op.create_table('adminunitorg', op.create_table(
sa.Column('id', sa.Integer(), nullable=False), "adminunitorg",
sa.Column('admin_unit_id', sa.Integer(), nullable=False), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('organization_id', sa.Integer(), nullable=False), sa.Column("admin_unit_id", sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['admin_unit_id'], ['adminunit.id'], ), sa.Column("organization_id", sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['organization_id'], ['organization.id'], ), sa.ForeignKeyConstraint(
sa.PrimaryKeyConstraint('id') ["admin_unit_id"],
["adminunit.id"],
),
sa.ForeignKeyConstraint(
["organization_id"],
["organization.id"],
),
sa.PrimaryKeyConstraint("id"),
) )
op.create_table('eventsuggestiondate', op.create_table(
sa.Column('id', sa.Integer(), nullable=False), "eventsuggestiondate",
sa.Column('event_suggestion_id', sa.Integer(), nullable=False), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('start', sa.DateTime(timezone=True), nullable=False), sa.Column("event_suggestion_id", sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['event_suggestion_id'], ['eventsuggestion.id'], ), sa.Column("start", sa.DateTime(timezone=True), nullable=False),
sa.PrimaryKeyConstraint('id') sa.ForeignKeyConstraint(
["event_suggestion_id"],
["eventsuggestion.id"],
),
sa.PrimaryKeyConstraint("id"),
) )
op.create_table('org_or_adminunit', op.create_table(
sa.Column('id', sa.Integer(), nullable=False), "org_or_adminunit",
sa.Column('organization_id', sa.Integer(), nullable=True), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('admin_unit_id', sa.Integer(), nullable=True), sa.Column("organization_id", sa.Integer(), nullable=True),
sa.CheckConstraint('NOT(organization_id IS NULL AND admin_unit_id IS NULL)'), sa.Column("admin_unit_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['admin_unit_id'], ['adminunit.id'], ), sa.CheckConstraint("NOT(organization_id IS NULL AND admin_unit_id IS NULL)"),
sa.ForeignKeyConstraint(['organization_id'], ['organization.id'], ), sa.ForeignKeyConstraint(
sa.PrimaryKeyConstraint('id'), ["admin_unit_id"],
sa.UniqueConstraint('organization_id', 'admin_unit_id') ["adminunit.id"],
),
sa.ForeignKeyConstraint(
["organization_id"],
["organization.id"],
),
sa.PrimaryKeyConstraint("id"),
sa.UniqueConstraint("organization_id", "admin_unit_id"),
) )
op.create_table('orgmember', op.create_table(
sa.Column('id', sa.Integer(), nullable=False), "orgmember",
sa.Column('organization_id', sa.Integer(), nullable=False), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('user_id', sa.Integer(), nullable=False), sa.Column("organization_id", sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['organization_id'], ['organization.id'], ), sa.Column("user_id", sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ), sa.ForeignKeyConstraint(
sa.PrimaryKeyConstraint('id') ["organization_id"],
["organization.id"],
),
sa.ForeignKeyConstraint(
["user_id"],
["user.id"],
),
sa.PrimaryKeyConstraint("id"),
) )
op.create_table('adminunitorgroles_organizations', op.create_table(
sa.Column('id', sa.Integer(), nullable=False), "adminunitorgroles_organizations",
sa.Column('admin_unit_org_id', sa.Integer(), nullable=True), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('role_id', sa.Integer(), nullable=True), sa.Column("admin_unit_org_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['admin_unit_org_id'], ['adminunitorg.id'], ), sa.Column("role_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['role_id'], ['adminunitorgrole.id'], ), sa.ForeignKeyConstraint(
sa.PrimaryKeyConstraint('id') ["admin_unit_org_id"],
["adminunitorg.id"],
),
sa.ForeignKeyConstraint(
["role_id"],
["adminunitorgrole.id"],
),
sa.PrimaryKeyConstraint("id"),
) )
op.create_table('event', op.create_table(
sa.Column('created_at', sa.DateTime(), nullable=True), "event",
sa.Column('id', sa.Integer(), nullable=False), sa.Column("created_at", sa.DateTime(), nullable=True),
sa.Column('admin_unit_id', sa.Integer(), nullable=False), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('host_id', sa.Integer(), nullable=False), sa.Column("admin_unit_id", sa.Integer(), nullable=False),
sa.Column('place_id', sa.Integer(), nullable=False), sa.Column("host_id", sa.Integer(), nullable=False),
sa.Column('name', sa.Unicode(length=255), nullable=False), sa.Column("place_id", sa.Integer(), nullable=False),
sa.Column('description', sa.UnicodeText(), nullable=False), sa.Column("name", sa.Unicode(length=255), nullable=False),
sa.Column('external_link', sa.String(length=255), nullable=True), sa.Column("description", sa.UnicodeText(), nullable=False),
sa.Column('ticket_link', sa.String(length=255), nullable=True), sa.Column("external_link", sa.String(length=255), nullable=True),
sa.Column('verified', sa.Boolean(), nullable=True), sa.Column("ticket_link", sa.String(length=255), nullable=True),
sa.Column('photo_id', sa.Integer(), nullable=True), sa.Column("verified", sa.Boolean(), nullable=True),
sa.Column('category_id', sa.Integer(), nullable=False), sa.Column("photo_id", sa.Integer(), nullable=True),
sa.Column('recurrence_rule', sa.UnicodeText(), nullable=True), sa.Column("category_id", sa.Integer(), nullable=False),
sa.Column('created_by_id', sa.Integer(), nullable=True), sa.Column("recurrence_rule", sa.UnicodeText(), nullable=True),
sa.ForeignKeyConstraint(['admin_unit_id'], ['adminunit.id'], ), sa.Column("created_by_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['category_id'], ['eventcategory.id'], ), sa.ForeignKeyConstraint(
sa.ForeignKeyConstraint(['created_by_id'], ['user.id'], ), ["admin_unit_id"],
sa.ForeignKeyConstraint(['host_id'], ['org_or_adminunit.id'], ), ["adminunit.id"],
sa.ForeignKeyConstraint(['photo_id'], ['image.id'], ), ),
sa.ForeignKeyConstraint(['place_id'], ['place.id'], ), sa.ForeignKeyConstraint(
sa.PrimaryKeyConstraint('id') ["category_id"],
["eventcategory.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('orgmemberroles_members', op.create_table(
sa.Column('id', sa.Integer(), nullable=False), "orgmemberroles_members",
sa.Column('member_id', sa.Integer(), nullable=True), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('role_id', sa.Integer(), nullable=True), sa.Column("member_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['member_id'], ['orgmember.id'], ), sa.Column("role_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['role_id'], ['orgmemberrole.id'], ), sa.ForeignKeyConstraint(
sa.PrimaryKeyConstraint('id') ["member_id"],
["orgmember.id"],
),
sa.ForeignKeyConstraint(
["role_id"],
["orgmemberrole.id"],
),
sa.PrimaryKeyConstraint("id"),
) )
op.create_table('eventdate', op.create_table(
sa.Column('id', sa.Integer(), nullable=False), "eventdate",
sa.Column('event_id', sa.Integer(), nullable=False), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('start', sa.DateTime(timezone=True), nullable=False), sa.Column("event_id", sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['event_id'], ['event.id'], ), sa.Column("start", sa.DateTime(timezone=True), nullable=False),
sa.PrimaryKeyConstraint('id') sa.ForeignKeyConstraint(
["event_id"],
["event.id"],
),
sa.PrimaryKeyConstraint("id"),
) )
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_table('eventdate') op.drop_table("eventdate")
op.drop_table('orgmemberroles_members') op.drop_table("orgmemberroles_members")
op.drop_table('event') op.drop_table("event")
op.drop_table('adminunitorgroles_organizations') op.drop_table("adminunitorgroles_organizations")
op.drop_table('orgmember') op.drop_table("orgmember")
op.drop_table('org_or_adminunit') op.drop_table("org_or_adminunit")
op.drop_table('eventsuggestiondate') op.drop_table("eventsuggestiondate")
op.drop_table('adminunitorg') op.drop_table("adminunitorg")
op.drop_table('adminunitmemberroles_members') op.drop_table("adminunitmemberroles_members")
op.drop_table('actor') op.drop_table("actor")
op.drop_table('place') op.drop_table("place")
op.drop_table('organization') op.drop_table("organization")
op.drop_table('eventsuggestion') op.drop_table("eventsuggestion")
op.drop_table('adminunitmember') op.drop_table("adminunitmember")
op.drop_table('roles_users') op.drop_table("roles_users")
op.drop_table('location') op.drop_table("location")
op.drop_table('image') op.drop_table("image")
op.drop_table('adminunit') op.drop_table("adminunit")
op.drop_table('user') op.drop_table("user")
op.drop_table('role') op.drop_table("role")
op.drop_table('orgmemberrole') op.drop_table("orgmemberrole")
op.drop_table('eventcategory') op.drop_table("eventcategory")
op.drop_table('adminunitorgrole') op.drop_table("adminunitorgrole")
op.drop_table('adminunitmemberrole') op.drop_table("adminunitmemberrole")
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -12,21 +12,25 @@ from project import dbtypes
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = 'cce1284874fa' revision = "cce1284874fa"
down_revision = 'b128cc637447' down_revision = "b128cc637447"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.add_column('adminunit', sa.Column('short_name', sa.Unicode(length=100), nullable=True)) op.add_column(
op.add_column('organization', sa.Column('short_name', sa.Unicode(length=100), nullable=True)) "adminunit", sa.Column("short_name", sa.Unicode(length=100), nullable=True)
)
op.add_column(
"organization", sa.Column("short_name", sa.Unicode(length=100), nullable=True)
)
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_column('organization', 'short_name') op.drop_column("organization", "short_name")
op.drop_column('adminunit', 'short_name') op.drop_column("adminunit", "short_name")
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -12,29 +12,40 @@ from project import dbtypes
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = 'da63ba1d58b1' revision = "da63ba1d58b1"
down_revision = '091deace5f08' down_revision = "091deace5f08"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
#op.drop_table('spatial_ref_sys') # op.drop_table('spatial_ref_sys')
op.add_column('image', sa.Column('copyright_text', sa.Unicode(length=255), nullable=True)) op.add_column(
"image", sa.Column("copyright_text", sa.Unicode(length=255), nullable=True)
)
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_column('image', 'copyright_text') op.drop_column("image", "copyright_text")
op.create_table('spatial_ref_sys', op.create_table(
sa.Column('srid', sa.INTEGER(), autoincrement=False, nullable=False), "spatial_ref_sys",
sa.Column('auth_name', sa.VARCHAR(length=256), autoincrement=False, nullable=True), sa.Column("srid", sa.INTEGER(), autoincrement=False, nullable=False),
sa.Column('auth_srid', sa.INTEGER(), autoincrement=False, nullable=True), sa.Column(
sa.Column('srtext', sa.VARCHAR(length=2048), autoincrement=False, nullable=True), "auth_name", sa.VARCHAR(length=256), autoincrement=False, nullable=True
sa.Column('proj4text', sa.VARCHAR(length=2048), autoincrement=False, nullable=True), ),
sa.CheckConstraint('(srid > 0) AND (srid <= 998999)', name='spatial_ref_sys_srid_check'), sa.Column("auth_srid", sa.INTEGER(), autoincrement=False, nullable=True),
sa.PrimaryKeyConstraint('srid', name='spatial_ref_sys_pkey') sa.Column(
"srtext", sa.VARCHAR(length=2048), autoincrement=False, nullable=True
),
sa.Column(
"proj4text", sa.VARCHAR(length=2048), autoincrement=False, nullable=True
),
sa.CheckConstraint(
"(srid > 0) AND (srid <= 998999)", name="spatial_ref_sys_srid_check"
),
sa.PrimaryKeyConstraint("srid", name="spatial_ref_sys_pkey"),
) )
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -12,25 +12,27 @@ from project import dbtypes
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = 'dcd0b71650b0' revision = "dcd0b71650b0"
down_revision = '699c4f6a7fe8' down_revision = "699c4f6a7fe8"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.add_column('eventorganizer', sa.Column('location_id', sa.Integer(), nullable=True)) op.add_column(
op.add_column('eventorganizer', sa.Column('logo_id', sa.Integer(), nullable=True)) "eventorganizer", sa.Column("location_id", sa.Integer(), nullable=True)
op.create_foreign_key(None, 'eventorganizer', 'image', ['logo_id'], ['id']) )
op.create_foreign_key(None, 'eventorganizer', 'location', ['location_id'], ['id']) op.add_column("eventorganizer", sa.Column("logo_id", sa.Integer(), nullable=True))
op.create_foreign_key(None, "eventorganizer", "image", ["logo_id"], ["id"])
op.create_foreign_key(None, "eventorganizer", "location", ["location_id"], ["id"])
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'eventorganizer', type_='foreignkey') op.drop_constraint(None, "eventorganizer", type_="foreignkey")
op.drop_constraint(None, 'eventorganizer', type_='foreignkey') op.drop_constraint(None, "eventorganizer", type_="foreignkey")
op.drop_column('eventorganizer', 'logo_id') op.drop_column("eventorganizer", "logo_id")
op.drop_column('eventorganizer', 'location_id') op.drop_column("eventorganizer", "location_id")
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -7,26 +7,29 @@ Create Date: 2020-07-08 08:53:44.373606
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
import sqlalchemy_utils
from project import dbtypes
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = 'ed6bb2084bbd' revision = "ed6bb2084bbd"
down_revision = 'f1bc3fa623c7' down_revision = "f1bc3fa623c7"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.add_column('event', sa.Column('previous_start_date', sa.DateTime(timezone=True), nullable=True)) op.add_column(
op.add_column('eventdate', sa.Column('end', sa.DateTime(timezone=True), nullable=True)) "event",
sa.Column("previous_start_date", sa.DateTime(timezone=True), nullable=True),
)
op.add_column(
"eventdate", sa.Column("end", sa.DateTime(timezone=True), nullable=True)
)
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_column('eventdate', 'end') op.drop_column("eventdate", "end")
op.drop_column('event', 'previous_start_date') op.drop_column("event", "previous_start_date")
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -7,38 +7,53 @@ Create Date: 2020-07-07 15:49:58.653888
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
import sqlalchemy_utils
from project import dbtypes from project import dbtypes
from project.models import EventTargetGroupOrigin, EventAttendanceMode, EventStatus from project.models import EventTargetGroupOrigin, EventAttendanceMode, EventStatus
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = 'f1bc3fa623c7' revision = "f1bc3fa623c7"
down_revision = '75c07cb9cfe3' down_revision = "75c07cb9cfe3"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.add_column('event', sa.Column('accessible_for_free', sa.Boolean(), nullable=True)) op.add_column(
op.add_column('event', sa.Column('age_from', sa.Integer(), nullable=True)) "event", sa.Column("accessible_for_free", sa.Boolean(), nullable=True)
op.add_column('event', sa.Column('age_to', sa.Integer(), nullable=True)) )
op.add_column('event', sa.Column('attendance_mode', dbtypes.IntegerEnum(EventAttendanceMode), nullable=True)) op.add_column("event", sa.Column("age_from", sa.Integer(), nullable=True))
op.add_column('event', sa.Column('kid_friendly', sa.Boolean(), nullable=True)) op.add_column("event", sa.Column("age_to", sa.Integer(), nullable=True))
op.add_column('event', sa.Column('status', dbtypes.IntegerEnum(EventStatus), nullable=True)) op.add_column(
op.add_column('event', sa.Column('tags', sa.UnicodeText(), nullable=True)) "event",
op.add_column('event', sa.Column('target_group_origin', dbtypes.IntegerEnum(EventTargetGroupOrigin), nullable=True)) sa.Column(
"attendance_mode", dbtypes.IntegerEnum(EventAttendanceMode), nullable=True
),
)
op.add_column("event", sa.Column("kid_friendly", sa.Boolean(), nullable=True))
op.add_column(
"event", sa.Column("status", dbtypes.IntegerEnum(EventStatus), nullable=True)
)
op.add_column("event", sa.Column("tags", sa.UnicodeText(), nullable=True))
op.add_column(
"event",
sa.Column(
"target_group_origin",
dbtypes.IntegerEnum(EventTargetGroupOrigin),
nullable=True,
),
)
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_column('event', 'target_group_origin') op.drop_column("event", "target_group_origin")
op.drop_column('event', 'tags') op.drop_column("event", "tags")
op.drop_column('event', 'status') op.drop_column("event", "status")
op.drop_column('event', 'kid_friendly') op.drop_column("event", "kid_friendly")
op.drop_column('event', 'attendance_mode') op.drop_column("event", "attendance_mode")
op.drop_column('event', 'age_to') op.drop_column("event", "age_to")
op.drop_column('event', 'age_from') op.drop_column("event", "age_from")
op.drop_column('event', 'accessible_for_free') op.drop_column("event", "accessible_for_free")
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -12,23 +12,29 @@ from project import dbtypes
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = 'f71c86333bfb' revision = "f71c86333bfb"
down_revision = '4e913af88c33' down_revision = "4e913af88c33"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.add_column('analytics', sa.Column('value1', sa.Unicode(length=255), nullable=True)) op.add_column(
op.add_column('analytics', sa.Column('value2', sa.Unicode(length=255), nullable=True)) "analytics", sa.Column("value1", sa.Unicode(length=255), nullable=True)
op.drop_column('analytics', 'value') )
op.add_column(
"analytics", sa.Column("value2", sa.Unicode(length=255), nullable=True)
)
op.drop_column("analytics", "value")
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.add_column('analytics', sa.Column('value', sa.TEXT(), autoincrement=False, nullable=True)) op.add_column(
op.drop_column('analytics', 'value2') "analytics", sa.Column("value", sa.TEXT(), autoincrement=False, nullable=True)
op.drop_column('analytics', 'value1') )
op.drop_column("analytics", "value2")
op.drop_column("analytics", "value1")
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -12,36 +12,46 @@ from project import dbtypes
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = 'fd7794ece0b3' revision = "fd7794ece0b3"
down_revision = '975c22ae802b' down_revision = "975c22ae802b"
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.create_table('eventplace', op.create_table(
sa.Column('created_at', sa.DateTime(), nullable=True), "eventplace",
sa.Column('id', sa.Integer(), nullable=False), sa.Column("created_at", sa.DateTime(), nullable=True),
sa.Column('name', sa.Unicode(length=255), nullable=False), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('location_id', sa.Integer(), nullable=True), sa.Column("name", sa.Unicode(length=255), nullable=False),
sa.Column('photo_id', sa.Integer(), nullable=True), sa.Column("location_id", sa.Integer(), nullable=True),
sa.Column('url', sa.String(length=255), nullable=True), sa.Column("photo_id", sa.Integer(), nullable=True),
sa.Column('description', sa.UnicodeText(), nullable=True), sa.Column("url", sa.String(length=255), nullable=True),
sa.Column('created_by_id', sa.Integer(), nullable=True), sa.Column("description", sa.UnicodeText(), nullable=True),
sa.ForeignKeyConstraint(['created_by_id'], ['user.id'], ), sa.Column("created_by_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['location_id'], ['location.id'], ), sa.ForeignKeyConstraint(
sa.ForeignKeyConstraint(['photo_id'], ['image.id'], ), ["created_by_id"],
sa.PrimaryKeyConstraint('id') ["user.id"],
),
sa.ForeignKeyConstraint(
["location_id"],
["location.id"],
),
sa.ForeignKeyConstraint(
["photo_id"],
["image.id"],
),
sa.PrimaryKeyConstraint("id"),
) )
op.add_column('event', sa.Column('event_place_id', sa.Integer(), nullable=True)) op.add_column("event", sa.Column("event_place_id", sa.Integer(), nullable=True))
op.create_foreign_key(None, 'event', 'place', ['event_place_id'], ['id']) op.create_foreign_key(None, "event", "place", ["event_place_id"], ["id"])
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'event', type_='foreignkey') op.drop_constraint(None, "event", type_="foreignkey")
op.drop_column('event', 'event_place_id') op.drop_column("event", "event_place_id")
op.drop_table('eventplace') op.drop_table("eventplace")
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -1,46 +1,45 @@
import os import os
from base64 import b64decode from flask import Flask
from flask import jsonify, Flask, render_template, request, url_for, redirect, abort, flash, current_app
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.orm import joinedload from flask_security import (
from sqlalchemy.sql import asc, func Security,
from sqlalchemy import and_, or_, not_, event SQLAlchemySessionUserDatastore,
from flask_security import Security, current_user, auth_required, roles_required, SQLAlchemySessionUserDatastore )
from flask_security.utils import FsPermNeed from flask_babelex import Babel
from flask_babelex import Babel, gettext, lazy_gettext, format_datetime, to_user_timezone
from flask_principal import Permission
from flask_cors import CORS from flask_cors import CORS
import pytz
import json
from flask_qrcode import QRcode from flask_qrcode import QRcode
from flask_mail import Mail, Message, email_dispatched from flask_mail import Mail, email_dispatched
# Create app # Create app
app = Flask(__name__) app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ['DATABASE_URL'] app.config["SQLALCHEMY_DATABASE_URI"] = os.environ["DATABASE_URL"]
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config['SECURITY_CONFIRMABLE'] = False app.config["SECURITY_CONFIRMABLE"] = False
app.config['SECURITY_TRACKABLE'] = True app.config["SECURITY_TRACKABLE"] = True
app.config['SECURITY_REGISTERABLE'] = True app.config["SECURITY_REGISTERABLE"] = True
app.config['SECURITY_SEND_REGISTER_EMAIL'] = False app.config["SECURITY_SEND_REGISTER_EMAIL"] = False
app.config['SECURITY_RECOVERABLE'] = True app.config["SECURITY_RECOVERABLE"] = True
app.config['SECURITY_CHANGEABLE'] = True app.config["SECURITY_CHANGEABLE"] = True
app.config['SECURITY_EMAIL_SENDER'] = os.getenv("MAIL_DEFAULT_SENDER") app.config["SECURITY_EMAIL_SENDER"] = os.getenv("MAIL_DEFAULT_SENDER")
app.config['LANGUAGES'] = ['en', 'de'] app.config["LANGUAGES"] = ["en", "de"]
app.config['GOOGLE_OAUTH_CLIENT_ID'] = os.getenv('GOOGLE_OAUTH_CLIENT_ID') app.config["GOOGLE_OAUTH_CLIENT_ID"] = os.getenv("GOOGLE_OAUTH_CLIENT_ID")
app.config['GOOGLE_OAUTH_CLIENT_SECRET'] = os.getenv('GOOGLE_OAUTH_CLIENT_SECRET') app.config["GOOGLE_OAUTH_CLIENT_SECRET"] = os.getenv("GOOGLE_OAUTH_CLIENT_SECRET")
app.config['OAUTHLIB_INSECURE_TRANSPORT'] = True app.config["OAUTHLIB_INSECURE_TRANSPORT"] = True
app.config['OAUTHLIB_RELAX_TOKEN_SCOPE'] = True app.config["OAUTHLIB_RELAX_TOKEN_SCOPE"] = True
# Generate a nice key using secrets.token_urlsafe() # Generate a nice key using secrets.token_urlsafe()
app.config['SECRET_KEY'] = os.environ.get("SECRET_KEY", 'pf9Wkove4IKEAXvy-cQkeDPhv9Cb3Ag-wyJILbq_dFw') app.config["SECRET_KEY"] = os.environ.get(
"SECRET_KEY", "pf9Wkove4IKEAXvy-cQkeDPhv9Cb3Ag-wyJILbq_dFw"
)
# Bcrypt is set as default SECURITY_PASSWORD_HASH, which requires a salt # Bcrypt is set as default SECURITY_PASSWORD_HASH, which requires a salt
# Generate a good salt using: secrets.SystemRandom().getrandbits(128) # Generate a good salt using: secrets.SystemRandom().getrandbits(128)
app.config['SECURITY_PASSWORD_SALT'] = os.environ.get("SECURITY_PASSWORD_SALT", '146585145368132386173505678016728509634') app.config["SECURITY_PASSWORD_SALT"] = os.environ.get(
"SECURITY_PASSWORD_SALT", "146585145368132386173505678016728509634"
)
# i18n # i18n
app.config['BABEL_DEFAULT_LOCALE'] = 'de' app.config["BABEL_DEFAULT_LOCALE"] = "de"
app.config['BABEL_DEFAULT_TIMEZONE'] = 'Europe/Berlin' app.config["BABEL_DEFAULT_TIMEZONE"] = "Europe/Berlin"
babel = Babel(app) babel = Babel(app)
# cors # cors
@ -50,24 +49,26 @@ cors = CORS(app, resources={r"/api/*": {"origins": "*"}})
mail_server = os.getenv("MAIL_SERVER") mail_server = os.getenv("MAIL_SERVER")
if mail_server is None: if mail_server is None:
app.config['MAIL_SUPPRESS_SEND'] = True app.config["MAIL_SUPPRESS_SEND"] = True
app.config['MAIL_DEFAULT_SENDER'] = 'test@oveda.de' app.config["MAIL_DEFAULT_SENDER"] = "test@oveda.de"
else: else:
app.config['MAIL_SUPPRESS_SEND'] = False app.config["MAIL_SUPPRESS_SEND"] = False
app.config['MAIL_SERVER'] = mail_server app.config["MAIL_SERVER"] = mail_server
app.config['MAIL_PORT'] = os.getenv("MAIL_PORT") app.config["MAIL_PORT"] = os.getenv("MAIL_PORT")
app.config['MAIL_USE_TLS'] = os.getenv("MAIL_USE_TLS", True) app.config["MAIL_USE_TLS"] = os.getenv("MAIL_USE_TLS", True)
app.config['MAIL_USE_SSL'] = os.getenv("MAIL_USE_SSL", False) app.config["MAIL_USE_SSL"] = os.getenv("MAIL_USE_SSL", False)
app.config['MAIL_USERNAME'] = os.getenv("MAIL_USERNAME") app.config["MAIL_USERNAME"] = os.getenv("MAIL_USERNAME")
app.config['MAIL_PASSWORD'] = os.getenv("MAIL_PASSWORD") app.config["MAIL_PASSWORD"] = os.getenv("MAIL_PASSWORD")
app.config['MAIL_DEFAULT_SENDER'] = os.getenv("MAIL_DEFAULT_SENDER") app.config["MAIL_DEFAULT_SENDER"] = os.getenv("MAIL_DEFAULT_SENDER")
mail = Mail(app) mail = Mail(app)
if app.config['MAIL_SUPPRESS_SEND']: if app.config["MAIL_SUPPRESS_SEND"]:
def log_message(message, app): def log_message(message, app):
print(message.subject) print(message.subject)
print(message.body) print(message.body)
email_dispatched.connect(log_message) email_dispatched.connect(log_message)
# Create db # Create db
@ -78,20 +79,23 @@ QRcode(app)
# JSON # JSON
from project.jsonld import DateTimeEncoder from project.jsonld import DateTimeEncoder
app.json_encoder = DateTimeEncoder app.json_encoder = DateTimeEncoder
# Setup Flask-Security # Setup Flask-Security
from project.models import User, Role from project.models import User, Role
user_datastore = SQLAlchemySessionUserDatastore(db.session, User, Role) user_datastore = SQLAlchemySessionUserDatastore(db.session, User, Role)
security = Security(app, user_datastore) security = Security(app, user_datastore)
# OAuth # OAuth
from project.oauth import blueprint from project.oauth import blueprint
app.register_blueprint(blueprint, url_prefix="/login") app.register_blueprint(blueprint, url_prefix="/login")
from project.i10n import * from project import i10n
from project.jinja_filters import * from project import jinja_filters
from project.init_data import * from project import init_data
# Routes # Routes
from project.views import ( from project.views import (
@ -113,8 +117,8 @@ from project.views import (
reference_request_review, reference_request_review,
root, root,
user, user,
widget widget,
) )
if __name__ == '__main__': if __name__ == "__main__":
app.run() app.run()

View File

@ -4,23 +4,29 @@ from flask_security.utils import FsPermNeed
from flask_principal import Permission from flask_principal import Permission
from project.models import AdminUnitMember, AdminUnit from project.models import AdminUnitMember, AdminUnit
def has_current_user_permission(permission): def has_current_user_permission(permission):
user_perm = Permission(FsPermNeed(permission)) user_perm = Permission(FsPermNeed(permission))
return user_perm.can() return user_perm.can()
def has_admin_unit_member_permission(admin_unit_member, permission): def has_admin_unit_member_permission(admin_unit_member, permission):
for role in admin_unit_member.roles: for role in admin_unit_member.roles:
if permission in role.get_permissions(): if permission in role.get_permissions():
return True return True
return False return False
def has_current_user_member_permission_for_admin_unit(admin_unit_id, permission): def has_current_user_member_permission_for_admin_unit(admin_unit_id, permission):
admin_unit_member = AdminUnitMember.query.filter_by(admin_unit_id=admin_unit_id, user_id=current_user.id).first() admin_unit_member = AdminUnitMember.query.filter_by(
admin_unit_id=admin_unit_id, user_id=current_user.id
).first()
if admin_unit_member is not None: if admin_unit_member is not None:
if has_admin_unit_member_permission(admin_unit_member, permission): if has_admin_unit_member_permission(admin_unit_member, permission):
return True return True
return False return False
def has_current_user_permission_for_admin_unit(admin_unit, permission): def has_current_user_permission_for_admin_unit(admin_unit, permission):
if not current_user.is_authenticated: if not current_user.is_authenticated:
return False return False
@ -33,40 +39,54 @@ def has_current_user_permission_for_admin_unit(admin_unit, permission):
return False return False
def has_access(admin_unit, permission): def has_access(admin_unit, permission):
return has_current_user_permission_for_admin_unit(admin_unit, permission) return has_current_user_permission_for_admin_unit(admin_unit, permission)
def access_or_401(admin_unit, permission): def access_or_401(admin_unit, permission):
if not has_access(admin_unit, permission): if not has_access(admin_unit, permission):
abort(401) abort(401)
def can_list_admin_unit_members(admin_unit): def can_list_admin_unit_members(admin_unit):
return has_current_user_permission_for_admin_unit(admin_unit, 'admin_unit.members:read') return has_current_user_permission_for_admin_unit(
admin_unit, "admin_unit.members:read"
)
def can_create_event(admin_unit): def can_create_event(admin_unit):
return has_current_user_permission_for_admin_unit(admin_unit, 'event:create') return has_current_user_permission_for_admin_unit(admin_unit, "event:create")
def can_update_event(event): def can_update_event(event):
return has_current_user_permission_for_admin_unit(event.admin_unit, 'event:update') return has_current_user_permission_for_admin_unit(event.admin_unit, "event:update")
def can_delete_event(event): def can_delete_event(event):
return has_current_user_permission_for_admin_unit(event.admin_unit, 'event:delete') return has_current_user_permission_for_admin_unit(event.admin_unit, "event:delete")
def can_reference_event(event): def can_reference_event(event):
return len(get_admin_units_for_event_reference(event)) > 0 return len(get_admin_units_for_event_reference(event)) > 0
def can_update_organizer(organizer): def can_update_organizer(organizer):
return get_admin_unit_for_manage(organizer.admin_unit_id) is not None return get_admin_unit_for_manage(organizer.admin_unit_id) is not None
def can_create_admin_unit(): def can_create_admin_unit():
return current_user.is_authenticated return current_user.is_authenticated
def can_verify_event_for_admin_unit(admin_unit): def can_verify_event_for_admin_unit(admin_unit):
return has_current_user_permission_for_admin_unit(admin_unit, 'event:verify') return has_current_user_permission_for_admin_unit(admin_unit, "event:verify")
def can_verify_event(event): def can_verify_event(event):
return can_verify_event_for_admin_unit(event.admin_unit) return can_verify_event_for_admin_unit(event.admin_unit)
def get_admin_units_with_current_user_permission(permission): def get_admin_units_with_current_user_permission(permission):
result = list() result = list()
@ -77,41 +97,48 @@ def get_admin_units_with_current_user_permission(permission):
return result return result
def get_admin_units_for_event_reference(event): def get_admin_units_for_event_reference(event):
result = list() result = list()
admin_units = get_admin_units_with_current_user_permission('event:reference') admin_units = get_admin_units_with_current_user_permission("event:reference")
for admin_unit in admin_units: for admin_unit in admin_units:
if admin_unit.id != event.admin_unit_id: if admin_unit.id != event.admin_unit_id:
result.append(admin_unit) result.append(admin_unit)
return result return result
def admin_units_the_current_user_is_member_of(): def admin_units_the_current_user_is_member_of():
result = list() result = list()
if current_user.is_authenticated: if current_user.is_authenticated:
admin_unit_members = AdminUnitMember.query.filter_by(user_id=current_user.id).all() admin_unit_members = AdminUnitMember.query.filter_by(
user_id=current_user.id
).all()
for admin_unit_member in admin_unit_members: for admin_unit_member in admin_unit_members:
result.append(admin_unit_member.adminunit) result.append(admin_unit_member.adminunit)
return result return result
def get_admin_units_for_manage(): def get_admin_units_for_manage():
# Global admin # Global admin
if current_user.has_role('admin'): if current_user.has_role("admin"):
return AdminUnit.query.all() return AdminUnit.query.all()
return admin_units_the_current_user_is_member_of() return admin_units_the_current_user_is_member_of()
def get_admin_unit_for_manage(admin_unit_id): def get_admin_unit_for_manage(admin_unit_id):
admin_units = get_admin_units_for_manage() admin_units = get_admin_units_for_manage()
return next((au for au in admin_units if au.id == admin_unit_id), None) return next((au for au in admin_units if au.id == admin_unit_id), None)
def get_admin_unit_for_manage_or_404(admin_unit_id): def get_admin_unit_for_manage_or_404(admin_unit_id):
admin_unit = get_admin_unit_for_manage(admin_unit_id) admin_unit = get_admin_unit_for_manage(admin_unit_id)
if not admin_unit: if not admin_unit:
abort(404) abort(404)
return admin_unit return admin_unit

View File

@ -1,41 +1,58 @@
import pytz import pytz
from dateutil import rrule from dateutil.rrule import rrulestr
from dateutil.rrule import rrulestr, rruleset, rrule
from datetime import datetime from datetime import datetime
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
berlin_tz = pytz.timezone('Europe/Berlin') berlin_tz = pytz.timezone("Europe/Berlin")
now = datetime.now(tz=berlin_tz) now = datetime.now(tz=berlin_tz)
today = datetime(now.year, now.month, now.day, tzinfo=now.tzinfo) today = datetime(now.year, now.month, now.day, tzinfo=now.tzinfo)
def create_berlin_date(year, month, day, hour, minute = 0):
def create_berlin_date(year, month, day, hour, minute=0):
return berlin_tz.localize(datetime(year, month, day, hour=hour, minute=minute)) return berlin_tz.localize(datetime(year, month, day, hour=hour, minute=minute))
def date_add_time(date, hour=0, minute=0, second=0, tzinfo=None): def date_add_time(date, hour=0, minute=0, second=0, tzinfo=None):
return datetime(date.year, date.month, date.day, hour=hour, minute=minute, second=second, tzinfo=tzinfo) return datetime(
date.year,
date.month,
date.day,
hour=hour,
minute=minute,
second=second,
tzinfo=tzinfo,
)
def date_set_end_of_day(date): def date_set_end_of_day(date):
return date_add_time(date, hour=23, minute=59, second=59) return date_add_time(date, hour=23, minute=59, second=59)
def form_input_to_date(date_str, hour=0, minute=0, second=0): def form_input_to_date(date_str, hour=0, minute=0, second=0):
date = datetime.strptime(date_str, "%Y-%m-%d") date = datetime.strptime(date_str, "%Y-%m-%d")
date_time = date_add_time(date, hour=hour, minute=minute, second=second) date_time = date_add_time(date, hour=hour, minute=minute, second=second)
return berlin_tz.localize(date_time) return berlin_tz.localize(date_time)
def form_input_from_date(date): def form_input_from_date(date):
return date.strftime("%Y-%m-%d") return date.strftime("%Y-%m-%d")
def dates_from_recurrence_rule(start, recurrence_rule): def dates_from_recurrence_rule(start, recurrence_rule):
result = list() result = list()
adv_recurrence_rule = recurrence_rule.replace('T000000', 'T235959') adv_recurrence_rule = recurrence_rule.replace("T000000", "T235959")
start_wo_tz = start.replace(tzinfo=None) start_wo_tz = start.replace(tzinfo=None)
rule_set = rrulestr(adv_recurrence_rule, forceset=True, dtstart=start_wo_tz) rule_set = rrulestr(adv_recurrence_rule, forceset=True, dtstart=start_wo_tz)
start_date = start_wo_tz start_date = start_wo_tz
end_date = start_date + relativedelta(years=1) end_date = start_date + relativedelta(years=1)
start_date_begin_of_day = datetime(start_date.year, start_date.month, start_date.day) start_date_begin_of_day = datetime(
end_date_end_of_day = datetime(end_date.year, end_date.month, end_date.day, hour=23, minute=59, second=59) start_date.year, start_date.month, start_date.day
)
end_date_end_of_day = datetime(
end_date.year, end_date.month, end_date.day, hour=23, minute=59, second=59
)
for rule_date in rule_set.between(start_date_begin_of_day, end_date_end_of_day): for rule_date in rule_set.between(start_date_begin_of_day, end_date_end_of_day):
rule_data_w_tz = berlin_tz.localize(rule_date) rule_data_w_tz = berlin_tz.localize(rule_date)
@ -43,7 +60,9 @@ def dates_from_recurrence_rule(start, recurrence_rule):
return result return result
BATCH_DELTA = 3 # How many batches to show before + after current batch
BATCH_DELTA = 3 # How many batches to show before + after current batch
def calculate_occurrences(start_date, date_format, rrule_str, start, batch_size): def calculate_occurrences(start_date, date_format, rrule_str, start, batch_size):
# TODO: Return error on failure # TODO: Return error on failure
@ -53,9 +72,9 @@ def calculate_occurrences(start_date, date_format, rrule_str, start, batch_size)
iterator = iter(rule) iterator = iter(rule)
cur_batch = start // batch_size cur_batch = start // batch_size
start = cur_batch * batch_size # Avoid stupid start-values start = cur_batch * batch_size # Avoid stupid start-values
if hasattr(rule, '_exdate'): if hasattr(rule, "_exdate"):
exdates = sorted(rule._exdate) exdates = sorted(rule._exdate)
else: else:
exdates = [] exdates = []
@ -79,13 +98,17 @@ def calculate_occurrences(start_date, date_format, rrule_str, start, batch_size)
else: else:
# include them # include them
exdate = exdates.pop(0) exdate = exdates.pop(0)
occurrences.append({'date': exdate.strftime('%Y%m%dT%H%M%S'), occurrences.append(
'formattedDate': exdate.strftime(date_format), {
'type': 'exdate',}) "date": exdate.strftime("%Y%m%dT%H%M%S"),
"formattedDate": exdate.strftime(date_format),
"type": "exdate",
}
)
i += 1 i += 1
if i >= batch_size + start: if i >= batch_size + start:
break # We are done! break # We are done!
i += 1 i += 1
if i <= start: if i <= start:
@ -93,24 +116,32 @@ def calculate_occurrences(start_date, date_format, rrule_str, start, batch_size)
continue continue
# Add it to the results # Add it to the results
if date in getattr(rule, '_rdate', []): if date in getattr(rule, "_rdate", []):
occurrence_type = 'rdate' occurrence_type = "rdate"
elif date == start_date: elif date == start_date:
occurrence_type = 'start' occurrence_type = "start"
else: else:
occurrence_type = 'rrule' occurrence_type = "rrule"
occurrences.append({'date': date.strftime('%Y%m%dT%H%M%S'), occurrences.append(
'formattedDate': date.strftime(date_format), {
'type': occurrence_type,}) "date": date.strftime("%Y%m%dT%H%M%S"),
"formattedDate": date.strftime(date_format),
"type": occurrence_type,
}
)
while exdates: while exdates:
# There are exdates that are after the end of the recurrence. # There are exdates that are after the end of the recurrence.
# Excluding the last dates make no sense, as you can change the # Excluding the last dates make no sense, as you can change the
# range instead, but we need to support it anyway. # range instead, but we need to support it anyway.
exdate = exdates.pop(0) exdate = exdates.pop(0)
occurrences.append({'date': exdate.strftime('%Y%m%dT%H%M%S'), occurrences.append(
'formattedDate': exdate.strftime(date_format), {
'type': 'exdate',}) "date": exdate.strftime("%Y%m%dT%H%M%S"),
"formattedDate": exdate.strftime(date_format),
"type": "exdate",
}
)
# Calculate no of occurrences, but only to a max of three times # Calculate no of occurrences, but only to a max of three times
# the batch size. This will support infinite recurrence in a # the batch size. This will support infinite recurrence in a
@ -132,18 +163,21 @@ def calculate_occurrences(start_date, date_format, rrule_str, start, batch_size)
# Total number of occurrences: # Total number of occurrences:
num_occurrences += batch_size + start num_occurrences += batch_size + start
max_batch = (num_occurrences - 1)//batch_size max_batch = (num_occurrences - 1) // batch_size
if last_batch > max_batch: if last_batch > max_batch:
last_batch = max_batch last_batch = max_batch
first_batch = max(0, max_batch - (BATCH_DELTA * 2)) first_batch = max(0, max_batch - (BATCH_DELTA * 2))
batches = [((x * batch_size) + 1, (x + 1) * batch_size) for x in range(first_batch, last_batch + 1)] batches = [
batch_data = {'start': start, ((x * batch_size) + 1, (x + 1) * batch_size)
'end': num_occurrences, for x in range(first_batch, last_batch + 1)
'batch_size': batch_size, ]
'batches': batches, batch_data = {
'currentBatch': cur_batch - first_batch, "start": start,
} "end": num_occurrences,
"batch_size": batch_size,
return {'occurrences': occurrences, 'batch': batch_data} "batches": batches,
"currentBatch": cur_batch - first_batch,
}
return {"occurrences": occurrences, "batch": batch_data}

View File

@ -1,8 +1,10 @@
from sqlalchemy.types import TypeDecorator from sqlalchemy.types import TypeDecorator
from sqlalchemy import Integer from sqlalchemy import Integer
class IntegerEnum(TypeDecorator): class IntegerEnum(TypeDecorator):
impl = Integer impl = Integer
def __init__(self, enumtype, *args, **kwargs): def __init__(self, enumtype, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self._enumtype = enumtype self._enumtype = enumtype

View File

@ -1,49 +1,90 @@
from flask_babelex import lazy_gettext from flask_babelex import lazy_gettext
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileAllowed from wtforms import (
from wtforms import StringField, SubmitField, DecimalField, TextAreaField, FormField, SelectField StringField,
SubmitField,
DecimalField,
FormField,
)
from wtforms.fields.html5 import EmailField, TelField, URLField from wtforms.fields.html5 import EmailField, TelField, URLField
from wtforms.validators import DataRequired, Optional, Regexp from wtforms.validators import DataRequired, Optional, Regexp
from wtforms.widgets.html5 import ColorInput from wtforms.widgets.html5 import ColorInput
import decimal
from project.models import Location, Image from project.models import Location, Image
from project.forms.common import FileImageForm from project.forms.common import FileImageForm
class AdminUnitLocationForm(FlaskForm): class AdminUnitLocationForm(FlaskForm):
street = StringField(lazy_gettext('Street'), validators=[Optional()]) street = StringField(lazy_gettext("Street"), validators=[Optional()])
postalCode = StringField(lazy_gettext('Postal code'), validators=[DataRequired()]) postalCode = StringField(lazy_gettext("Postal code"), validators=[DataRequired()])
city = StringField(lazy_gettext('City'), validators=[DataRequired()]) city = StringField(lazy_gettext("City"), validators=[DataRequired()])
state = StringField(lazy_gettext('State'), validators=[Optional()]) state = StringField(lazy_gettext("State"), validators=[Optional()])
latitude = DecimalField(lazy_gettext('Latitude'), places=16, validators=[Optional()]) latitude = DecimalField(
longitude = DecimalField(lazy_gettext('Longitude'), places=16, validators=[Optional()]) lazy_gettext("Latitude"), places=16, validators=[Optional()]
)
longitude = DecimalField(
lazy_gettext("Longitude"), places=16, validators=[Optional()]
)
class BaseAdminUnitForm(FlaskForm): class BaseAdminUnitForm(FlaskForm):
name = StringField(lazy_gettext('Name'), validators=[DataRequired()]) name = StringField(lazy_gettext("Name"), validators=[DataRequired()])
short_name = StringField(lazy_gettext('Short name'), description=lazy_gettext('The short name is used to create a unique identifier for your events'), validators=[DataRequired(), Regexp('^\w+$', message=lazy_gettext("Short name must contain only letters numbers or underscore"))]) short_name = StringField(
url = URLField(lazy_gettext('Link URL'), validators=[Optional()]) lazy_gettext("Short name"),
email = EmailField(lazy_gettext('Email'), validators=[Optional()]) description=lazy_gettext(
phone = TelField(lazy_gettext('Phone'), validators=[Optional()]) "The short name is used to create a unique identifier for your events"
fax = TelField(lazy_gettext('Fax'), validators=[Optional()]) ),
logo = FormField(FileImageForm, lazy_gettext('Logo'), default=lambda: Image()) validators=[
DataRequired(),
Regexp(
r"^\w+$",
message=lazy_gettext(
"Short name must contain only letters numbers or underscore"
),
),
],
)
url = URLField(lazy_gettext("Link URL"), validators=[Optional()])
email = EmailField(lazy_gettext("Email"), validators=[Optional()])
phone = TelField(lazy_gettext("Phone"), validators=[Optional()])
fax = TelField(lazy_gettext("Fax"), validators=[Optional()])
logo = FormField(FileImageForm, lazy_gettext("Logo"), default=lambda: Image())
location = FormField(AdminUnitLocationForm, default=lambda: Location()) location = FormField(AdminUnitLocationForm, default=lambda: Location())
def populate_obj(self, obj): def populate_obj(self, obj):
for name, field in self._fields.items(): for name, field in self._fields.items():
if name == 'location' and not obj.location: if name == "location" and not obj.location:
obj.location = Location() obj.location = Location()
elif name == 'logo' and not obj.logo: elif name == "logo" and not obj.logo:
obj.logo = Image() obj.logo = Image()
field.populate_obj(obj, name) field.populate_obj(obj, name)
class CreateAdminUnitForm(BaseAdminUnitForm): class CreateAdminUnitForm(BaseAdminUnitForm):
submit = SubmitField(lazy_gettext("Create admin unit")) submit = SubmitField(lazy_gettext("Create admin unit"))
class UpdateAdminUnitForm(BaseAdminUnitForm): class UpdateAdminUnitForm(BaseAdminUnitForm):
submit = SubmitField(lazy_gettext("Update settings")) submit = SubmitField(lazy_gettext("Update settings"))
class UpdateAdminUnitWidgetForm(FlaskForm): class UpdateAdminUnitWidgetForm(FlaskForm):
widget_font = StringField(lazy_gettext('Font'), validators=[Optional()]) widget_font = StringField(lazy_gettext("Font"), validators=[Optional()])
widget_background_color = StringField(lazy_gettext('Background Color'), default='#ffffff', widget=ColorInput(), validators=[Optional()]) widget_background_color = StringField(
widget_primary_color = StringField(lazy_gettext('Primary Color'), default='#007bff', widget=ColorInput(), validators=[Optional()]) lazy_gettext("Background Color"),
widget_link_color = StringField(lazy_gettext('Link Color'), default='#007bff', widget=ColorInput(), validators=[Optional()]) default="#ffffff",
submit = SubmitField(lazy_gettext("Update settings")) widget=ColorInput(),
validators=[Optional()],
)
widget_primary_color = StringField(
lazy_gettext("Primary Color"),
default="#007bff",
widget=ColorInput(),
validators=[Optional()],
)
widget_link_color = StringField(
lazy_gettext("Link Color"),
default="#007bff",
widget=ColorInput(),
validators=[Optional()],
)
submit = SubmitField(lazy_gettext("Update settings"))

View File

@ -1,31 +1,32 @@
from flask_babelex import lazy_gettext from flask_babelex import lazy_gettext
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileAllowed from wtforms import SubmitField
from wtforms import StringField, SubmitField, DecimalField, TextAreaField, FormField, SelectField from wtforms.fields.html5 import EmailField
from wtforms.fields.html5 import EmailField, TelField from wtforms.validators import DataRequired
from wtforms.validators import DataRequired, Optional, Regexp
import decimal
from project.models import Location
from project.forms.widgets import MultiCheckboxField from project.forms.widgets import MultiCheckboxField
class InviteAdminUnitMemberForm(FlaskForm): class InviteAdminUnitMemberForm(FlaskForm):
email = EmailField(lazy_gettext('Email'), validators=[DataRequired()]) email = EmailField(lazy_gettext("Email"), validators=[DataRequired()])
roles = MultiCheckboxField(lazy_gettext('Roles')) roles = MultiCheckboxField(lazy_gettext("Roles"))
submit = SubmitField(lazy_gettext("Invite")) submit = SubmitField(lazy_gettext("Invite"))
class NegotiateAdminUnitMemberInvitationForm(FlaskForm): class NegotiateAdminUnitMemberInvitationForm(FlaskForm):
accept = SubmitField(lazy_gettext("Accept")) accept = SubmitField(lazy_gettext("Accept"))
decline = SubmitField(lazy_gettext("Decline")) decline = SubmitField(lazy_gettext("Decline"))
class DeleteAdminUnitInvitationForm(FlaskForm): class DeleteAdminUnitInvitationForm(FlaskForm):
submit = SubmitField(lazy_gettext("Delete invitation")) submit = SubmitField(lazy_gettext("Delete invitation"))
email = EmailField(lazy_gettext('Email'), validators=[DataRequired()]) email = EmailField(lazy_gettext("Email"), validators=[DataRequired()])
class DeleteAdminUnitMemberForm(FlaskForm): class DeleteAdminUnitMemberForm(FlaskForm):
submit = SubmitField(lazy_gettext("Delete member")) submit = SubmitField(lazy_gettext("Delete member"))
email = EmailField(lazy_gettext('Email'), validators=[DataRequired()]) email = EmailField(lazy_gettext("Email"), validators=[DataRequired()])
class UpdateAdminUnitMemberForm(FlaskForm): class UpdateAdminUnitMemberForm(FlaskForm):
roles = MultiCheckboxField(lazy_gettext('Roles')) roles = MultiCheckboxField(lazy_gettext("Roles"))
submit = SubmitField(lazy_gettext("Update member")) submit = SubmitField(lazy_gettext("Update member"))

View File

@ -2,16 +2,25 @@ from flask_babelex import lazy_gettext
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileAllowed from flask_wtf.file import FileField, FileAllowed
from wtforms import StringField, BooleanField, HiddenField from wtforms import StringField, BooleanField, HiddenField
from wtforms.validators import DataRequired, Optional from wtforms.validators import Optional
import re import re
import base64 import base64
class BaseImageForm(FlaskForm): class BaseImageForm(FlaskForm):
copyright_text = StringField(lazy_gettext('Copyright text'), validators=[Optional()]) copyright_text = StringField(
lazy_gettext("Copyright text"), validators=[Optional()]
)
class FileImageForm(BaseImageForm): class FileImageForm(BaseImageForm):
image_file = FileField(lazy_gettext('File'), validators=[FileAllowed(['jpg', 'jpeg', 'png'], lazy_gettext('Images only!'))]) image_file = FileField(
delete_flag = BooleanField(lazy_gettext('Delete image'), default=False, validators=[Optional()]) lazy_gettext("File"),
validators=[FileAllowed(["jpg", "jpeg", "png"], lazy_gettext("Images only!"))],
)
delete_flag = BooleanField(
lazy_gettext("Delete image"), default=False, validators=[Optional()]
)
def populate_obj(self, obj): def populate_obj(self, obj):
super(BaseImageForm, self).populate_obj(obj) super(BaseImageForm, self).populate_obj(obj)
@ -24,6 +33,7 @@ class FileImageForm(BaseImageForm):
obj.data = None obj.data = None
obj.encoding_format = None obj.encoding_format = None
class Base64ImageForm(BaseImageForm): class Base64ImageForm(BaseImageForm):
image_base64 = HiddenField() image_base64 = HiddenField()
@ -31,8 +41,10 @@ class Base64ImageForm(BaseImageForm):
super(BaseImageForm, self).process(formdata, obj, data, **kwargs) super(BaseImageForm, self).process(formdata, obj, data, **kwargs)
if self.image_base64.data is None and obj and obj.data: if self.image_base64.data is None and obj and obj.data:
base64_str = base64.b64encode(obj.data).decode('utf-8') base64_str = base64.b64encode(obj.data).decode("utf-8")
self.image_base64.data = 'data:{};base64,{}'.format(obj.encoding_format, base64_str) self.image_base64.data = "data:{};base64,{}".format(
obj.encoding_format, base64_str
)
def populate_obj(self, obj): def populate_obj(self, obj):
super(BaseImageForm, self).populate_obj(obj) super(BaseImageForm, self).populate_obj(obj)
@ -49,35 +61,36 @@ class Base64ImageForm(BaseImageForm):
obj.data = None obj.data = None
obj.encoding_format = None obj.encoding_format = None
event_rating_choices = [ event_rating_choices = [
(0,lazy_gettext('0 (Little relevant)')), (0, lazy_gettext("0 (Little relevant)")),
(10,'1'), (10, "1"),
(20,'2'), (20, "2"),
(30,'3'), (30, "3"),
(40,'4'), (40, "4"),
(50,'5'), (50, "5"),
(60,'6'), (60, "6"),
(70,'7'), (70, "7"),
(80,'8'), (80, "8"),
(90,'9'), (90, "9"),
(100,lazy_gettext('10 (Highlight)')) (100, lazy_gettext("10 (Highlight)")),
] ]
weekday_choices = [ weekday_choices = [
(1,lazy_gettext('Monday')), (1, lazy_gettext("Monday")),
(2,lazy_gettext('Tueday')), (2, lazy_gettext("Tueday")),
(3,lazy_gettext('Wednesday')), (3, lazy_gettext("Wednesday")),
(4,lazy_gettext('Thursday')), (4, lazy_gettext("Thursday")),
(5,lazy_gettext('Friday')), (5, lazy_gettext("Friday")),
(6,lazy_gettext('Saturday')), (6, lazy_gettext("Saturday")),
(0,lazy_gettext('Sunday')) (0, lazy_gettext("Sunday")),
] ]
distance_choices = [ distance_choices = [
(500,lazy_gettext('500 m')), (500, lazy_gettext("500 m")),
(5000,lazy_gettext('5 km')), (5000, lazy_gettext("5 km")),
(10000,lazy_gettext('10 km')), (10000, lazy_gettext("10 km")),
(25000,lazy_gettext('20 km')), (25000, lazy_gettext("20 km")),
(50000,lazy_gettext('50 km')), (50000, lazy_gettext("50 km")),
(100000,lazy_gettext('100 km')) (100000, lazy_gettext("100 km")),
] ]

View File

@ -1,100 +1,183 @@
from flask import request from flask import request
from flask_babelex import lazy_gettext, gettext from flask_babelex import lazy_gettext, gettext
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileAllowed from wtforms import (
from wtforms import SelectMultipleField, FieldList, RadioField, DateTimeField, StringField, SubmitField, TextAreaField, SelectField, BooleanField, IntegerField, FormField SelectMultipleField,
from wtforms.fields.html5 import DateTimeLocalField, EmailField, URLField RadioField,
StringField,
SubmitField,
TextAreaField,
SelectField,
BooleanField,
IntegerField,
FormField,
)
from wtforms.fields.html5 import EmailField, URLField
from wtforms.validators import DataRequired, Optional from wtforms.validators import DataRequired, Optional
from wtforms.widgets import html_params, HTMLString from project.models import (
from project.models import EventPlace, EventTargetGroupOrigin, EventAttendanceMode, EventStatus, Location, EventOrganizer, EventRejectionReason, EventReviewStatus, Image EventPlace,
EventTargetGroupOrigin,
EventAttendanceMode,
EventStatus,
Location,
EventOrganizer,
Image,
)
from project.forms.common import event_rating_choices, Base64ImageForm from project.forms.common import event_rating_choices, Base64ImageForm
from project.forms.widgets import CustomDateTimeField, CustomDateField from project.forms.widgets import CustomDateTimeField, CustomDateField
class EventPlaceLocationForm(FlaskForm): class EventPlaceLocationForm(FlaskForm):
street = StringField(lazy_gettext('Street'), validators=[Optional()]) street = StringField(lazy_gettext("Street"), validators=[Optional()])
postalCode = StringField(lazy_gettext('Postal code'), validators=[Optional()]) postalCode = StringField(lazy_gettext("Postal code"), validators=[Optional()])
city = StringField(lazy_gettext('City'), validators=[Optional()]) city = StringField(lazy_gettext("City"), validators=[Optional()])
class EventPlaceForm(FlaskForm): class EventPlaceForm(FlaskForm):
name = StringField(lazy_gettext('Name'), validators=[Optional()]) name = StringField(lazy_gettext("Name"), validators=[Optional()])
location = FormField(EventPlaceLocationForm, default=lambda: Location()) location = FormField(EventPlaceLocationForm, default=lambda: Location())
def populate_obj(self, obj): def populate_obj(self, obj):
for name, field in self._fields.items(): for name, field in self._fields.items():
if name == 'location' and not obj.location: if name == "location" and not obj.location:
obj.location = Location() obj.location = Location()
field.populate_obj(obj, name) field.populate_obj(obj, name)
class OrganizerForm(EventPlaceForm): class OrganizerForm(EventPlaceForm):
pass pass
class EventOrganizerForm(FlaskForm): class EventOrganizerForm(FlaskForm):
name = StringField(lazy_gettext('Organizator'), validators=[Optional()]) name = StringField(lazy_gettext("Organizator"), validators=[Optional()])
url = URLField(lazy_gettext('Link URL'), validators=[Optional()]) url = URLField(lazy_gettext("Link URL"), validators=[Optional()])
email = EmailField(lazy_gettext('Email'), validators=[Optional()]) email = EmailField(lazy_gettext("Email"), validators=[Optional()])
phone = StringField(lazy_gettext('Phone'), validators=[Optional()]) phone = StringField(lazy_gettext("Phone"), validators=[Optional()])
fax = StringField(lazy_gettext('Fax'), validators=[Optional()]) fax = StringField(lazy_gettext("Fax"), validators=[Optional()])
class BaseEventForm(FlaskForm): class BaseEventForm(FlaskForm):
name = StringField(lazy_gettext('Name'), validators=[DataRequired()]) name = StringField(lazy_gettext("Name"), validators=[DataRequired()])
external_link = URLField(lazy_gettext('Link URL'), validators=[Optional()]) external_link = URLField(lazy_gettext("Link URL"), validators=[Optional()])
ticket_link = StringField(lazy_gettext('Ticket Link URL'), validators=[Optional()]) ticket_link = StringField(lazy_gettext("Ticket Link URL"), validators=[Optional()])
description = TextAreaField(lazy_gettext('Description'), validators=[DataRequired()]) description = TextAreaField(
recurrence_rule = TextAreaField(lazy_gettext('Recurrence rule'), validators=[Optional()]) lazy_gettext("Description"), validators=[DataRequired()]
start = CustomDateTimeField(lazy_gettext('Start'), validators=[DataRequired()]) )
end = CustomDateTimeField(lazy_gettext('End'), validators=[Optional()]) recurrence_rule = TextAreaField(
previous_start_date = CustomDateTimeField(lazy_gettext('Previous start date'), validators=[Optional()]) lazy_gettext("Recurrence rule"), validators=[Optional()]
tags = StringField(lazy_gettext('Tags'), validators=[Optional()]) )
category_ids = SelectMultipleField(lazy_gettext('Categories'), validators=[DataRequired()], coerce=int) start = CustomDateTimeField(lazy_gettext("Start"), validators=[DataRequired()])
end = CustomDateTimeField(lazy_gettext("End"), validators=[Optional()])
previous_start_date = CustomDateTimeField(
lazy_gettext("Previous start date"), validators=[Optional()]
)
tags = StringField(lazy_gettext("Tags"), validators=[Optional()])
category_ids = SelectMultipleField(
lazy_gettext("Categories"), validators=[DataRequired()], coerce=int
)
kid_friendly = BooleanField(lazy_gettext('Kid friendly'), validators=[Optional()]) kid_friendly = BooleanField(lazy_gettext("Kid friendly"), validators=[Optional()])
accessible_for_free = BooleanField(lazy_gettext('Accessible for free'), validators=[Optional()]) accessible_for_free = BooleanField(
age_from = IntegerField(lazy_gettext('Typical Age from'), validators=[Optional()]) lazy_gettext("Accessible for free"), validators=[Optional()]
age_to = IntegerField(lazy_gettext('Typical Age to'), validators=[Optional()]) )
registration_required = BooleanField(lazy_gettext('Registration required'), validators=[Optional()]) age_from = IntegerField(lazy_gettext("Typical Age from"), validators=[Optional()])
booked_up = BooleanField(lazy_gettext('Booked up'), validators=[Optional()]) age_to = IntegerField(lazy_gettext("Typical Age to"), validators=[Optional()])
expected_participants = IntegerField(lazy_gettext('Expected number of participants'), validators=[Optional()]) registration_required = BooleanField(
price_info = TextAreaField(lazy_gettext('Price info'), validators=[Optional()]) lazy_gettext("Registration required"), validators=[Optional()]
)
booked_up = BooleanField(lazy_gettext("Booked up"), validators=[Optional()])
expected_participants = IntegerField(
lazy_gettext("Expected number of participants"), validators=[Optional()]
)
price_info = TextAreaField(lazy_gettext("Price info"), validators=[Optional()])
target_group_origin = SelectField(lazy_gettext('Target group origin'), coerce=int, choices=[ target_group_origin = SelectField(
(int(EventTargetGroupOrigin.both), lazy_gettext('EventTargetGroupOrigin.both')), lazy_gettext("Target group origin"),
(int(EventTargetGroupOrigin.tourist), lazy_gettext('EventTargetGroupOrigin.tourist')), coerce=int,
(int(EventTargetGroupOrigin.resident), lazy_gettext('EventTargetGroupOrigin.resident'))]) choices=[
(
int(EventTargetGroupOrigin.both),
lazy_gettext("EventTargetGroupOrigin.both"),
),
(
int(EventTargetGroupOrigin.tourist),
lazy_gettext("EventTargetGroupOrigin.tourist"),
),
(
int(EventTargetGroupOrigin.resident),
lazy_gettext("EventTargetGroupOrigin.resident"),
),
],
)
attendance_mode = SelectField(lazy_gettext('Attendance mode'), coerce=int, choices=[ attendance_mode = SelectField(
(int(EventAttendanceMode.offline), lazy_gettext('EventAttendanceMode.offline')), lazy_gettext("Attendance mode"),
(int(EventAttendanceMode.online), lazy_gettext('EventAttendanceMode.online')), coerce=int,
(int(EventAttendanceMode.mixed), lazy_gettext('EventAttendanceMode.mixed'))]) choices=[
(
int(EventAttendanceMode.offline),
lazy_gettext("EventAttendanceMode.offline"),
),
(
int(EventAttendanceMode.online),
lazy_gettext("EventAttendanceMode.online"),
),
(int(EventAttendanceMode.mixed), lazy_gettext("EventAttendanceMode.mixed")),
],
)
photo = FormField(Base64ImageForm, lazy_gettext("Photo"), default=lambda: Image())
rating = SelectField(
lazy_gettext("Rating"), default=50, coerce=int, choices=event_rating_choices
)
photo = FormField(Base64ImageForm, lazy_gettext('Photo'), default=lambda: Image())
rating = SelectField(lazy_gettext('Rating'), default=50, coerce=int, choices=event_rating_choices)
class CreateEventForm(BaseEventForm): class CreateEventForm(BaseEventForm):
event_place_choice = RadioField(lazy_gettext('Place'), choices=[(1,lazy_gettext('Select existing place')), (2,lazy_gettext('Enter new place'))], default=1, coerce=int) event_place_choice = RadioField(
event_place_id = SelectField(lazy_gettext('Place'), validators=[Optional()], coerce=int) lazy_gettext("Place"),
choices=[
(1, lazy_gettext("Select existing place")),
(2, lazy_gettext("Enter new place")),
],
default=1,
coerce=int,
)
event_place_id = SelectField(
lazy_gettext("Place"), validators=[Optional()], coerce=int
)
new_event_place = FormField(EventPlaceForm, default=lambda: EventPlace()) new_event_place = FormField(EventPlaceForm, default=lambda: EventPlace())
organizer_choice = RadioField(lazy_gettext('Organizer'), choices=[(1,lazy_gettext('Select existing organizer')), (2,lazy_gettext('Enter new organizer'))], default=1, coerce=int) organizer_choice = RadioField(
organizer_id = SelectField(lazy_gettext('Organizer'), validators=[Optional()], coerce=int) lazy_gettext("Organizer"),
choices=[
(1, lazy_gettext("Select existing organizer")),
(2, lazy_gettext("Enter new organizer")),
],
default=1,
coerce=int,
)
organizer_id = SelectField(
lazy_gettext("Organizer"), validators=[Optional()], coerce=int
)
new_organizer = FormField(OrganizerForm, default=lambda: EventOrganizer()) new_organizer = FormField(OrganizerForm, default=lambda: EventOrganizer())
submit = SubmitField(lazy_gettext("Create event")) submit = SubmitField(lazy_gettext("Create event"))
def populate_obj(self, obj): def populate_obj(self, obj):
for name, field in self._fields.items(): for name, field in self._fields.items():
if name == 'new_event_place': if name == "new_event_place":
if self.event_place_choice.data != 2: if self.event_place_choice.data != 2:
continue continue
if not obj.event_place: if not obj.event_place:
obj.event_place = EventPlace() obj.event_place = EventPlace()
field.populate_obj(obj, 'event_place') field.populate_obj(obj, "event_place")
elif name == 'new_organizer': elif name == "new_organizer":
if self.organizer_choice.data != 2: if self.organizer_choice.data != 2:
continue continue
if not obj.organizer: if not obj.organizer:
obj.organizer = EventOrganizer() obj.organizer = EventOrganizer()
field.populate_obj(obj, 'organizer') field.populate_obj(obj, "organizer")
elif name == 'photo' and not obj.photo: elif name == "photo" and not obj.photo:
obj.photo = Image() obj.photo = Image()
field.populate_obj(obj, name) field.populate_obj(obj, name)
@ -102,50 +185,67 @@ class CreateEventForm(BaseEventForm):
if not super(BaseEventForm, self).validate(): if not super(BaseEventForm, self).validate():
return False return False
if self.event_place_id.data == 0 and not self.new_event_place.form.name.data: if self.event_place_id.data == 0 and not self.new_event_place.form.name.data:
msg = gettext('Select existing place or enter new place') msg = gettext("Select existing place or enter new place")
self.event_place_id.errors.append(msg) self.event_place_id.errors.append(msg)
self.new_event_place.form.name.errors.append(msg) self.new_event_place.form.name.errors.append(msg)
return False return False
if self.organizer_id.data == 0 and not self.new_organizer.form.name.data: if self.organizer_id.data == 0 and not self.new_organizer.form.name.data:
msg = gettext('Select existing organizer or enter new organizer') msg = gettext("Select existing organizer or enter new organizer")
self.organizer_id.errors.append(msg) self.organizer_id.errors.append(msg)
self.new_organizer.form.name.errors.append(msg) self.new_organizer.form.name.errors.append(msg)
return False return False
return True return True
class UpdateEventForm(BaseEventForm):
event_place_id = SelectField(lazy_gettext('Place'), validators=[DataRequired()], coerce=int)
organizer_id = SelectField(lazy_gettext('Organizer'), validators=[DataRequired()], coerce=int)
status = SelectField(lazy_gettext('Status'), coerce=int, choices=[ class UpdateEventForm(BaseEventForm):
(int(EventStatus.scheduled), lazy_gettext('EventStatus.scheduled')), event_place_id = SelectField(
(int(EventStatus.cancelled), lazy_gettext('EventStatus.cancelled')), lazy_gettext("Place"), validators=[DataRequired()], coerce=int
(int(EventStatus.movedOnline), lazy_gettext('EventStatus.movedOnline')), )
(int(EventStatus.postponed), lazy_gettext('EventStatus.postponed')), organizer_id = SelectField(
(int(EventStatus.rescheduled), lazy_gettext('EventStatus.rescheduled'))]) lazy_gettext("Organizer"), validators=[DataRequired()], coerce=int
)
status = SelectField(
lazy_gettext("Status"),
coerce=int,
choices=[
(int(EventStatus.scheduled), lazy_gettext("EventStatus.scheduled")),
(int(EventStatus.cancelled), lazy_gettext("EventStatus.cancelled")),
(int(EventStatus.movedOnline), lazy_gettext("EventStatus.movedOnline")),
(int(EventStatus.postponed), lazy_gettext("EventStatus.postponed")),
(int(EventStatus.rescheduled), lazy_gettext("EventStatus.rescheduled")),
],
)
submit = SubmitField(lazy_gettext("Update event")) submit = SubmitField(lazy_gettext("Update event"))
def populate_obj(self, obj): def populate_obj(self, obj):
for name, field in self._fields.items(): for name, field in self._fields.items():
if name == 'photo' and not obj.photo: if name == "photo" and not obj.photo:
obj.photo = Image() obj.photo = Image()
field.populate_obj(obj, name) field.populate_obj(obj, name)
class DeleteEventForm(FlaskForm): class DeleteEventForm(FlaskForm):
submit = SubmitField(lazy_gettext("Delete event")) submit = SubmitField(lazy_gettext("Delete event"))
name = StringField(lazy_gettext('Name'), validators=[DataRequired()]) name = StringField(lazy_gettext("Name"), validators=[DataRequired()])
class FindEventForm(FlaskForm): class FindEventForm(FlaskForm):
class Meta: class Meta:
csrf = False csrf = False
date_from = CustomDateField(lazy_gettext('From'), validators=[Optional()])
date_to = CustomDateField(lazy_gettext('to'), validators=[Optional()]) date_from = CustomDateField(lazy_gettext("From"), validators=[Optional()])
keyword = StringField(lazy_gettext('Keyword'), validators=[Optional()]) date_to = CustomDateField(lazy_gettext("to"), validators=[Optional()])
category_id = SelectField(lazy_gettext('Category'), validators=[Optional()], coerce=int) keyword = StringField(lazy_gettext("Keyword"), validators=[Optional()])
organizer_id = SelectField(lazy_gettext('Organizer'), validators=[Optional()], coerce=int) category_id = SelectField(
lazy_gettext("Category"), validators=[Optional()], coerce=int
)
organizer_id = SelectField(
lazy_gettext("Organizer"), validators=[Optional()], coerce=int
)
submit = SubmitField(lazy_gettext("Find events")) submit = SubmitField(lazy_gettext("Find events"))
def is_submitted(self): def is_submitted(self):
return 'submit' in request.args return "submit" in request.args

View File

@ -1,28 +1,37 @@
from flask import request from flask import request
from flask_babelex import lazy_gettext, gettext from flask_babelex import lazy_gettext
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileAllowed from wtforms import (
from wtforms import HiddenField, SelectMultipleField, FieldList, RadioField, DateTimeField, StringField, SubmitField, TextAreaField, SelectField, BooleanField, IntegerField, FormField HiddenField,
from wtforms.fields.html5 import DateTimeLocalField, EmailField StringField,
from wtforms.validators import DataRequired, Optional SubmitField,
from wtforms.widgets import html_params, HTMLString SelectField,
from project.models import EventPlace, EventTargetGroupOrigin, EventAttendanceMode, EventStatus, Location, EventOrganizer, EventRejectionReason, EventReviewStatus )
from project.forms.common import event_rating_choices, weekday_choices, distance_choices from wtforms.validators import Optional
from project.forms.widgets import CustomDateField, MultiCheckboxField from project.forms.common import distance_choices
from project.forms.widgets import CustomDateField
class FindEventDateForm(FlaskForm): class FindEventDateForm(FlaskForm):
class Meta: class Meta:
csrf = False csrf = False
date_from = CustomDateField(lazy_gettext('From'), validators=[Optional()]) date_from = CustomDateField(lazy_gettext("From"), validators=[Optional()])
date_to = CustomDateField(lazy_gettext('to'), validators=[Optional()]) date_to = CustomDateField(lazy_gettext("to"), validators=[Optional()])
keyword = StringField(lazy_gettext('Keyword'), validators=[Optional()]) keyword = StringField(lazy_gettext("Keyword"), validators=[Optional()])
category_id = SelectField(lazy_gettext('Category'), validators=[Optional()], coerce=int) category_id = SelectField(
lazy_gettext("Category"), validators=[Optional()], coerce=int
)
coordinate = HiddenField(validators=[Optional()]) coordinate = HiddenField(validators=[Optional()])
location = StringField(lazy_gettext('Location'), validators=[Optional()]) location = StringField(lazy_gettext("Location"), validators=[Optional()])
distance = SelectField(lazy_gettext('Distance'), validators=[Optional()], coerce=int, choices=distance_choices) distance = SelectField(
lazy_gettext("Distance"),
validators=[Optional()],
coerce=int,
choices=distance_choices,
)
submit = SubmitField(lazy_gettext("Find")) submit = SubmitField(lazy_gettext("Find"))
def is_submitted(self): def is_submitted(self):
return 'submit' in request.args return "submit" in request.args

View File

@ -1,48 +1,62 @@
from flask_babelex import lazy_gettext, gettext from flask_babelex import lazy_gettext
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileAllowed from wtforms import (
from wtforms import DecimalField, RadioField, DateTimeField, StringField, SubmitField, TextAreaField, SelectField, BooleanField, IntegerField, FormField DecimalField,
from wtforms.fields.html5 import DateTimeLocalField, EmailField, URLField StringField,
SubmitField,
TextAreaField,
FormField,
)
from wtforms.fields.html5 import URLField
from wtforms.validators import DataRequired, Optional from wtforms.validators import DataRequired, Optional
from wtforms.widgets import html_params, HTMLString
import decimal
from project.models import Location, Image from project.models import Location, Image
from project.forms.common import FileImageForm from project.forms.common import FileImageForm
class EventPlaceLocationForm(FlaskForm): class EventPlaceLocationForm(FlaskForm):
street = StringField(lazy_gettext('Street'), validators=[Optional()]) street = StringField(lazy_gettext("Street"), validators=[Optional()])
postalCode = StringField(lazy_gettext('Postal code'), validators=[Optional()]) postalCode = StringField(lazy_gettext("Postal code"), validators=[Optional()])
city = StringField(lazy_gettext('City'), validators=[Optional()]) city = StringField(lazy_gettext("City"), validators=[Optional()])
state = StringField(lazy_gettext('State'), validators=[Optional()]) state = StringField(lazy_gettext("State"), validators=[Optional()])
latitude = DecimalField(lazy_gettext('Latitude'), places=16, validators=[Optional()]) latitude = DecimalField(
longitude = DecimalField(lazy_gettext('Longitude'), places=16, validators=[Optional()]) lazy_gettext("Latitude"), places=16, validators=[Optional()]
)
longitude = DecimalField(
lazy_gettext("Longitude"), places=16, validators=[Optional()]
)
class BaseEventPlaceForm(FlaskForm): class BaseEventPlaceForm(FlaskForm):
name = StringField(lazy_gettext('Name'), validators=[DataRequired()]) name = StringField(lazy_gettext("Name"), validators=[DataRequired()])
url = URLField(lazy_gettext('Link URL'), validators=[Optional()]) url = URLField(lazy_gettext("Link URL"), validators=[Optional()])
photo = FormField(FileImageForm, lazy_gettext('Photo'), default=lambda: Image()) photo = FormField(FileImageForm, lazy_gettext("Photo"), default=lambda: Image())
description = TextAreaField(lazy_gettext('Description'), validators=[Optional()]) description = TextAreaField(lazy_gettext("Description"), validators=[Optional()])
location = FormField(EventPlaceLocationForm) location = FormField(EventPlaceLocationForm)
def populate_obj(self, obj): def populate_obj(self, obj):
for name, field in self._fields.items(): for name, field in self._fields.items():
if name == 'location' and not obj.location: if name == "location" and not obj.location:
obj.location = Location() obj.location = Location()
elif name == 'photo' and not obj.photo: elif name == "photo" and not obj.photo:
obj.photo = Image() obj.photo = Image()
field.populate_obj(obj, name) field.populate_obj(obj, name)
class CreateEventPlaceForm(BaseEventPlaceForm): class CreateEventPlaceForm(BaseEventPlaceForm):
submit = SubmitField(lazy_gettext("Create place")) submit = SubmitField(lazy_gettext("Create place"))
class UpdateEventPlaceForm(BaseEventPlaceForm): class UpdateEventPlaceForm(BaseEventPlaceForm):
submit = SubmitField(lazy_gettext("Update place")) submit = SubmitField(lazy_gettext("Update place"))
class DeleteEventPlaceForm(FlaskForm): class DeleteEventPlaceForm(FlaskForm):
submit = SubmitField(lazy_gettext("Delete place")) submit = SubmitField(lazy_gettext("Delete place"))
name = StringField(lazy_gettext('Name'), validators=[DataRequired()]) name = StringField(lazy_gettext("Name"), validators=[DataRequired()])
class FindEventPlaceForm(FlaskForm): class FindEventPlaceForm(FlaskForm):
class Meta: class Meta:
csrf = False csrf = False
submit = SubmitField(lazy_gettext("Find places")) submit = SubmitField(lazy_gettext("Find places"))

View File

@ -1,52 +1,135 @@
from flask import request from flask_babelex import lazy_gettext
from flask_babelex import lazy_gettext, gettext
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileAllowed from wtforms import (
from wtforms import FieldList, RadioField, DateTimeField, StringField, SubmitField, TextAreaField, SelectField, BooleanField, IntegerField, FormField StringField,
from wtforms.fields.html5 import DateTimeLocalField, EmailField, TelField, URLField SubmitField,
TextAreaField,
SelectField,
BooleanField,
FormField,
)
from wtforms.fields.html5 import EmailField, TelField, URLField
from wtforms.validators import DataRequired, Optional from wtforms.validators import DataRequired, Optional
from wtforms.widgets import html_params, HTMLString from project.models import (
from project.models import EventSuggestion, EventPlace, EventTargetGroupOrigin, EventAttendanceMode, EventStatus, Location, EventOrganizer, EventRejectionReason, EventReviewStatus, Image EventRejectionReason,
from project.forms.common import event_rating_choices, Base64ImageForm Image,
from project.forms.widgets import CustomDateTimeField, CustomDateField, TagSelectField )
from project.forms.common import event_rating_choices from project.forms.common import Base64ImageForm
from project.forms.widgets import CustomDateTimeField, TagSelectField
class CreateEventSuggestionForm(FlaskForm): class CreateEventSuggestionForm(FlaskForm):
name = StringField(lazy_gettext('Name'), validators=[DataRequired()], description=lazy_gettext('Enter a short, meaningful name for the event.')) name = StringField(
start = CustomDateTimeField(lazy_gettext('Start'), validators=[DataRequired()], description=lazy_gettext('Indicate when the event will take place.')) lazy_gettext("Name"),
description = TextAreaField(lazy_gettext('Description'), validators=[Optional()], description=lazy_gettext('Add an optional description of the event.')) validators=[DataRequired()],
external_link = URLField(lazy_gettext('Link URL'), validators=[Optional()], description=lazy_gettext('Add an optional link. That can make the review easier.')) description=lazy_gettext("Enter a short, meaningful name for the event."),
)
start = CustomDateTimeField(
lazy_gettext("Start"),
validators=[DataRequired()],
description=lazy_gettext("Indicate when the event will take place."),
)
description = TextAreaField(
lazy_gettext("Description"),
validators=[Optional()],
description=lazy_gettext("Add an optional description of the event."),
)
external_link = URLField(
lazy_gettext("Link URL"),
validators=[Optional()],
description=lazy_gettext(
"Add an optional link. That can make the review easier."
),
)
contact_name = StringField(lazy_gettext('Name'), validators=[DataRequired()], description=lazy_gettext('Please enter your name for the review.')) contact_name = StringField(
contact_phone = TelField(lazy_gettext('Phone'), validators=[Optional()], description=lazy_gettext('Please enter your phone number or email address for the review.')) lazy_gettext("Name"),
contact_email = EmailField(lazy_gettext('Email'), validators=[Optional()], description=lazy_gettext('Please enter your email address or phone number for the review.')) validators=[DataRequired()],
contact_email_notice = BooleanField(lazy_gettext('I would like to be notified by email after the review'), validators=[Optional()]) description=lazy_gettext("Please enter your name for the review."),
)
contact_phone = TelField(
lazy_gettext("Phone"),
validators=[Optional()],
description=lazy_gettext(
"Please enter your phone number or email address for the review."
),
)
contact_email = EmailField(
lazy_gettext("Email"),
validators=[Optional()],
description=lazy_gettext(
"Please enter your email address or phone number for the review."
),
)
contact_email_notice = BooleanField(
lazy_gettext("I would like to be notified by email after the review"),
validators=[Optional()],
)
event_place_id = TagSelectField(lazy_gettext('Place'), validators=[DataRequired()], description=lazy_gettext('Choose where the event takes place. If the venue is not yet in the list, just enter it.')) event_place_id = TagSelectField(
organizer_id = TagSelectField(lazy_gettext('Organizer'), validators=[DataRequired()], description=lazy_gettext('Select the organizer. If the organizer is not yet on the list, just enter it.')) lazy_gettext("Place"),
photo = FormField(Base64ImageForm, lazy_gettext('Photo'), default=lambda: Image(), description=lazy_gettext('We recommend uploading a photo for the event. It looks a lot more, but of course it works without it.')) validators=[DataRequired()],
accept_tos = BooleanField(lazy_gettext('I confirm that I have clarified all information (text, images, etc.) that I upload into the system with regard to their rights of use and declare that they may be passed on.'), validators=[DataRequired()]) description=lazy_gettext(
"Choose where the event takes place. If the venue is not yet in the list, just enter it."
),
)
organizer_id = TagSelectField(
lazy_gettext("Organizer"),
validators=[DataRequired()],
description=lazy_gettext(
"Select the organizer. If the organizer is not yet on the list, just enter it."
),
)
photo = FormField(
Base64ImageForm,
lazy_gettext("Photo"),
default=lambda: Image(),
description=lazy_gettext(
"We recommend uploading a photo for the event. It looks a lot more, but of course it works without it."
),
)
accept_tos = BooleanField(
lazy_gettext(
"I confirm that I have clarified all information (text, images, etc.) that I upload into the system with regard to their rights of use and declare that they may be passed on."
),
validators=[DataRequired()],
)
submit = SubmitField(lazy_gettext("Create event suggestion")) submit = SubmitField(lazy_gettext("Create event suggestion"))
def populate_obj(self, obj): def populate_obj(self, obj):
for name, field in self._fields.items(): for name, field in self._fields.items():
if name == 'photo' and not obj.photo: if name == "photo" and not obj.photo:
obj.photo = Image() obj.photo = Image()
if name == 'event_place_id' and self.event_place_id.is_free_text(): if name == "event_place_id" and self.event_place_id.is_free_text():
obj.event_place_text = self.event_place_id.data obj.event_place_text = self.event_place_id.data
obj.event_place_id = None obj.event_place_id = None
elif name == 'organizer_id' and self.organizer_id.is_free_text(): elif name == "organizer_id" and self.organizer_id.is_free_text():
obj.organizer_text = self.organizer_id.data obj.organizer_text = self.organizer_id.data
obj.organizer_id = None obj.organizer_id = None
else: else:
field.populate_obj(obj, name) field.populate_obj(obj, name)
class RejectEventSuggestionForm(FlaskForm): class RejectEventSuggestionForm(FlaskForm):
rejection_resaon = SelectField(lazy_gettext('Rejection reason'), coerce=int, choices=[ rejection_resaon = SelectField(
(0, ''), lazy_gettext("Rejection reason"),
(int(EventRejectionReason.duplicate), lazy_gettext('EventRejectionReason.duplicate')), coerce=int,
(int(EventRejectionReason.untrustworthy), lazy_gettext('EventRejectionReason.untrustworthy')), choices=[
(int(EventRejectionReason.illegal), lazy_gettext('EventRejectionReason.illegal'))]) (0, ""),
(
int(EventRejectionReason.duplicate),
lazy_gettext("EventRejectionReason.duplicate"),
),
(
int(EventRejectionReason.untrustworthy),
lazy_gettext("EventRejectionReason.untrustworthy"),
),
(
int(EventRejectionReason.illegal),
lazy_gettext("EventRejectionReason.illegal"),
),
],
)
submit = SubmitField(lazy_gettext("Reject event suggestion")) submit = SubmitField(lazy_gettext("Reject event suggestion"))

View File

@ -1,44 +1,56 @@
from flask_babelex import lazy_gettext from flask_babelex import lazy_gettext
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileAllowed from wtforms import (
from wtforms import StringField, SubmitField, DecimalField, TextAreaField, FormField, SelectField StringField,
SubmitField,
DecimalField,
FormField,
)
from wtforms.fields.html5 import EmailField, TelField, URLField from wtforms.fields.html5 import EmailField, TelField, URLField
from wtforms.validators import DataRequired, Optional, Regexp from wtforms.validators import DataRequired, Optional
import decimal
from project.models import Location, Image from project.models import Location, Image
from project.forms.common import FileImageForm from project.forms.common import FileImageForm
class OrganizerLocationForm(FlaskForm): class OrganizerLocationForm(FlaskForm):
street = StringField(lazy_gettext('Street'), validators=[Optional()]) street = StringField(lazy_gettext("Street"), validators=[Optional()])
postalCode = StringField(lazy_gettext('Postal code'), validators=[Optional()]) postalCode = StringField(lazy_gettext("Postal code"), validators=[Optional()])
city = StringField(lazy_gettext('City'), validators=[Optional()]) city = StringField(lazy_gettext("City"), validators=[Optional()])
state = StringField(lazy_gettext('State'), validators=[Optional()]) state = StringField(lazy_gettext("State"), validators=[Optional()])
latitude = DecimalField(lazy_gettext('Latitude'), places=16, validators=[Optional()]) latitude = DecimalField(
longitude = DecimalField(lazy_gettext('Longitude'), places=16, validators=[Optional()]) lazy_gettext("Latitude"), places=16, validators=[Optional()]
)
longitude = DecimalField(
lazy_gettext("Longitude"), places=16, validators=[Optional()]
)
class BaseOrganizerForm(FlaskForm): class BaseOrganizerForm(FlaskForm):
name = StringField(lazy_gettext('Name'), validators=[DataRequired()]) name = StringField(lazy_gettext("Name"), validators=[DataRequired()])
url = URLField(lazy_gettext('Link URL'), validators=[Optional()]) url = URLField(lazy_gettext("Link URL"), validators=[Optional()])
email = EmailField(lazy_gettext('Email'), validators=[Optional()]) email = EmailField(lazy_gettext("Email"), validators=[Optional()])
phone = TelField(lazy_gettext('Phone'), validators=[Optional()]) phone = TelField(lazy_gettext("Phone"), validators=[Optional()])
fax = TelField(lazy_gettext('Fax'), validators=[Optional()]) fax = TelField(lazy_gettext("Fax"), validators=[Optional()])
logo = FormField(FileImageForm, lazy_gettext('Logo'), default=lambda: Image()) logo = FormField(FileImageForm, lazy_gettext("Logo"), default=lambda: Image())
location = FormField(OrganizerLocationForm) location = FormField(OrganizerLocationForm)
def populate_obj(self, obj): def populate_obj(self, obj):
for name, field in self._fields.items(): for name, field in self._fields.items():
if name == 'location' and not obj.location: if name == "location" and not obj.location:
obj.location = Location() obj.location = Location()
elif name == 'logo' and not obj.logo: elif name == "logo" and not obj.logo:
obj.logo = Image() obj.logo = Image()
field.populate_obj(obj, name) field.populate_obj(obj, name)
class CreateOrganizerForm(BaseOrganizerForm): class CreateOrganizerForm(BaseOrganizerForm):
submit = SubmitField(lazy_gettext("Create organizer")) submit = SubmitField(lazy_gettext("Create organizer"))
class UpdateOrganizerForm(BaseOrganizerForm): class UpdateOrganizerForm(BaseOrganizerForm):
submit = SubmitField(lazy_gettext("Update organizer")) submit = SubmitField(lazy_gettext("Update organizer"))
class DeleteOrganizerForm(FlaskForm): class DeleteOrganizerForm(FlaskForm):
submit = SubmitField(lazy_gettext("Delete organizer")) submit = SubmitField(lazy_gettext("Delete organizer"))
name = StringField(lazy_gettext('Name'), validators=[DataRequired()]) name = StringField(lazy_gettext("Name"), validators=[DataRequired()])

View File

@ -1,28 +1,37 @@
from flask import request from flask import request
from flask_babelex import lazy_gettext, gettext from flask_babelex import lazy_gettext
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileAllowed from wtforms import HiddenField, StringField, SubmitField, SelectField
from wtforms import HiddenField, SelectMultipleField, FieldList, RadioField, DateTimeField, StringField, SubmitField, TextAreaField, SelectField, BooleanField, IntegerField, FormField from wtforms.validators import Optional
from wtforms.fields.html5 import DateTimeLocalField, EmailField from project.forms.common import weekday_choices, distance_choices
from wtforms.validators import DataRequired, Optional
from wtforms.widgets import html_params, HTMLString
from project.models import EventPlace, EventTargetGroupOrigin, EventAttendanceMode, EventStatus, Location, EventOrganizer, EventRejectionReason, EventReviewStatus
from project.forms.common import event_rating_choices, weekday_choices, distance_choices
from project.forms.widgets import CustomDateField, MultiCheckboxField from project.forms.widgets import CustomDateField, MultiCheckboxField
class PlaningForm(FlaskForm): class PlaningForm(FlaskForm):
class Meta: class Meta:
csrf = False csrf = False
date_from = CustomDateField(lazy_gettext('From'), validators=[Optional()]) date_from = CustomDateField(lazy_gettext("From"), validators=[Optional()])
date_to = CustomDateField(lazy_gettext('to'), validators=[Optional()]) date_to = CustomDateField(lazy_gettext("to"), validators=[Optional()])
category_id = SelectField(lazy_gettext('Category'), validators=[Optional()], coerce=int) category_id = SelectField(
lazy_gettext("Category"), validators=[Optional()], coerce=int
)
coordinate = HiddenField(validators=[Optional()]) coordinate = HiddenField(validators=[Optional()])
location = StringField(lazy_gettext('Location'), validators=[Optional()]) location = StringField(lazy_gettext("Location"), validators=[Optional()])
distance = SelectField(lazy_gettext('Distance'), validators=[Optional()], coerce=int, choices=distance_choices) distance = SelectField(
weekday = MultiCheckboxField(lazy_gettext('Weekdays'), validators=[Optional()], coerce=int, choices=weekday_choices) lazy_gettext("Distance"),
validators=[Optional()],
coerce=int,
choices=distance_choices,
)
weekday = MultiCheckboxField(
lazy_gettext("Weekdays"),
validators=[Optional()],
coerce=int,
choices=weekday_choices,
)
submit = SubmitField(lazy_gettext("Find")) submit = SubmitField(lazy_gettext("Find"))
def is_submitted(self): def is_submitted(self):
return 'submit' in request.args return "submit" in request.args

View File

@ -1,18 +1,27 @@
from flask_babelex import lazy_gettext, gettext from flask_babelex import lazy_gettext
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from wtforms import SelectField, StringField, SubmitField from wtforms import SelectField, StringField, SubmitField
from wtforms.validators import DataRequired from wtforms.validators import DataRequired
from project.forms.common import event_rating_choices from project.forms.common import event_rating_choices
class CreateEventReferenceForm(FlaskForm): class CreateEventReferenceForm(FlaskForm):
admin_unit_id = SelectField(lazy_gettext('Admin unit'), validators=[DataRequired()], coerce=int) admin_unit_id = SelectField(
rating = SelectField(lazy_gettext('Rating'), default=50, coerce=int, choices=event_rating_choices) lazy_gettext("Admin unit"), validators=[DataRequired()], coerce=int
)
rating = SelectField(
lazy_gettext("Rating"), default=50, coerce=int, choices=event_rating_choices
)
submit = SubmitField(lazy_gettext("Save reference")) submit = SubmitField(lazy_gettext("Save reference"))
class UpdateEventReferenceForm(FlaskForm): class UpdateEventReferenceForm(FlaskForm):
rating = SelectField(lazy_gettext('Rating'), default=50, coerce=int, choices=event_rating_choices) rating = SelectField(
lazy_gettext("Rating"), default=50, coerce=int, choices=event_rating_choices
)
submit = SubmitField(lazy_gettext("Update reference")) submit = SubmitField(lazy_gettext("Update reference"))
class DeleteReferenceForm(FlaskForm): class DeleteReferenceForm(FlaskForm):
submit = SubmitField(lazy_gettext("Delete reference")) submit = SubmitField(lazy_gettext("Delete reference"))
name = StringField(lazy_gettext('Name'), validators=[DataRequired()]) name = StringField(lazy_gettext("Name"), validators=[DataRequired()])

View File

@ -1,30 +1,71 @@
from flask_babelex import lazy_gettext, gettext from flask_babelex import lazy_gettext
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from wtforms import SelectField, StringField, SubmitField from wtforms import SelectField, StringField, SubmitField
from wtforms.validators import DataRequired from wtforms.validators import DataRequired
from project.forms.common import event_rating_choices from project.forms.common import event_rating_choices
from project.models import EventReferenceRequestRejectionReason, EventReferenceRequestReviewStatus from project.models import (
EventReferenceRequestRejectionReason,
EventReferenceRequestReviewStatus,
)
class CreateEventReferenceRequestForm(FlaskForm): class CreateEventReferenceRequestForm(FlaskForm):
admin_unit_id = SelectField(lazy_gettext('Admin unit'), validators=[DataRequired()], coerce=int) admin_unit_id = SelectField(
lazy_gettext("Admin unit"), validators=[DataRequired()], coerce=int
)
submit = SubmitField(lazy_gettext("Save request")) submit = SubmitField(lazy_gettext("Save request"))
class DeleteReferenceRequestForm(FlaskForm): class DeleteReferenceRequestForm(FlaskForm):
submit = SubmitField(lazy_gettext("Delete request")) submit = SubmitField(lazy_gettext("Delete request"))
name = StringField(lazy_gettext('Name'), validators=[DataRequired()]) name = StringField(lazy_gettext("Name"), validators=[DataRequired()])
class ReferenceRequestReviewForm(FlaskForm): class ReferenceRequestReviewForm(FlaskForm):
review_status = SelectField(lazy_gettext('Review status'), coerce=int, choices=[ review_status = SelectField(
(int(EventReferenceRequestReviewStatus.inbox), lazy_gettext('EventReferenceRequestReviewStatus.inbox')), lazy_gettext("Review status"),
(int(EventReferenceRequestReviewStatus.verified), lazy_gettext('EventReferenceRequestReviewStatus.verified')), coerce=int,
(int(EventReferenceRequestReviewStatus.rejected), lazy_gettext('EventReferenceRequestReviewStatus.rejected'))]) choices=[
(
int(EventReferenceRequestReviewStatus.inbox),
lazy_gettext("EventReferenceRequestReviewStatus.inbox"),
),
(
int(EventReferenceRequestReviewStatus.verified),
lazy_gettext("EventReferenceRequestReviewStatus.verified"),
),
(
int(EventReferenceRequestReviewStatus.rejected),
lazy_gettext("EventReferenceRequestReviewStatus.rejected"),
),
],
)
rejection_reason = SelectField(lazy_gettext('Rejection reason'), coerce=int, choices=[ rejection_reason = SelectField(
(0, ''), lazy_gettext("Rejection reason"),
(int(EventReferenceRequestRejectionReason.duplicate), lazy_gettext('EventReferenceRequestRejectionReason.duplicate')), coerce=int,
(int(EventReferenceRequestRejectionReason.untrustworthy), lazy_gettext('EventReferenceRequestRejectionReason.untrustworthy')), choices=[
(int(EventReferenceRequestRejectionReason.irrelevant), lazy_gettext('EventReferenceRequestRejectionReason.irrelevant')), (0, ""),
(int(EventReferenceRequestRejectionReason.illegal), lazy_gettext('EventReferenceRequestRejectionReason.illegal'))]) (
int(EventReferenceRequestRejectionReason.duplicate),
lazy_gettext("EventReferenceRequestRejectionReason.duplicate"),
),
(
int(EventReferenceRequestRejectionReason.untrustworthy),
lazy_gettext("EventReferenceRequestRejectionReason.untrustworthy"),
),
(
int(EventReferenceRequestRejectionReason.irrelevant),
lazy_gettext("EventReferenceRequestRejectionReason.irrelevant"),
),
(
int(EventReferenceRequestRejectionReason.illegal),
lazy_gettext("EventReferenceRequestRejectionReason.illegal"),
),
],
)
rating = SelectField(lazy_gettext('Rating'), default=50, coerce=int, choices=event_rating_choices) rating = SelectField(
submit = SubmitField(lazy_gettext("Save review")) lazy_gettext("Rating"), default=50, coerce=int, choices=event_rating_choices
)
submit = SubmitField(lazy_gettext("Save review"))

View File

@ -1,15 +1,16 @@
from wtforms import DateTimeField, SelectMultipleField, SelectField from wtforms import DateTimeField, SelectMultipleField, SelectField
from wtforms.widgets import html_params, HTMLString, ListWidget, CheckboxInput from wtforms.widgets import html_params, HTMLString, ListWidget, CheckboxInput
from wtforms.validators import StopValidation from wtforms.validators import StopValidation
import pytz
from datetime import datetime from datetime import datetime
from flask_babelex import to_user_timezone, gettext from flask_babelex import to_user_timezone, gettext
from project.dateutils import berlin_tz from project.dateutils import berlin_tz
class MultiCheckboxField(SelectMultipleField): class MultiCheckboxField(SelectMultipleField):
widget = ListWidget(prefix_label=False) widget = ListWidget(prefix_label=False)
option_widget = CheckboxInput() option_widget = CheckboxInput()
def create_option_string(count, value): def create_option_string(count, value):
result = "" result = ""
for i in range(count): for i in range(count):
@ -17,10 +18,11 @@ def create_option_string(count, value):
result = result + '<option value="%02d"%s>%02d</option>' % (i, selected, i) result = result + '<option value="%02d"%s>%02d</option>' % (i, selected, i)
return result return result
class CustomDateTimeWidget: class CustomDateTimeWidget:
def __call__(self, field, **kwargs): def __call__(self, field, **kwargs):
id = kwargs.pop('id', field.id) id = kwargs.pop("id", field.id)
date = '' date = ""
hour = minute = 0 hour = minute = 0
if field.data: if field.data:
date_value = to_user_timezone(field.data) date_value = to_user_timezone(field.data)
@ -28,12 +30,24 @@ class CustomDateTimeWidget:
hour = date_value.hour hour = date_value.hour
minute = date_value.minute minute = date_value.minute
date_params = html_params(name=field.name, id=id, value=date, required=field.flags.required, **kwargs) date_params = html_params(
time_hour_params = html_params(name=field.name, id=id + '-hour', **kwargs) name=field.name, id=id, value=date, required=field.flags.required, **kwargs
time_minute_params = html_params(name=field.name, id=id + '-minute', **kwargs) )
clear_button_id = id + '-clear-button' time_hour_params = html_params(name=field.name, id=id + "-hour", **kwargs)
time_minute_params = html_params(name=field.name, id=id + "-minute", **kwargs)
clear_button_id = id + "-clear-button"
return HTMLString(
'<div class="input-group-prepend mt-1"><input type="text" class="datepicker" {}/><button class="btn btn-outline-secondary" type="button" id="{}"><i class="fa fa-times"></i></button></div><div class="mx-2"></div><div class="input-group-append mt-1"><select {}>{}</select><span class="input-group-text">:</span><select {}>{}</select></div>'.format(
date_params,
clear_button_id,
time_hour_params,
create_option_string(24, hour),
time_minute_params,
create_option_string(60, minute),
)
)
return HTMLString('<div class="input-group-prepend mt-1"><input type="text" class="datepicker" {}/><button class="btn btn-outline-secondary" type="button" id="{}"><i class="fa fa-times"></i></button></div><div class="mx-2"></div><div class="input-group-append mt-1"><select {}>{}</select><span class="input-group-text">:</span><select {}>{}</select></div>'.format(date_params, clear_button_id, time_hour_params, create_option_string(24, hour), time_minute_params, create_option_string(60, minute)))
class CustomDateTimeField(DateTimeField): class CustomDateTimeField(DateTimeField):
widget = CustomDateTimeWidget() widget = CustomDateTimeWidget()
@ -47,15 +61,20 @@ class CustomDateTimeField(DateTimeField):
return return
date = datetime.strptime(date_str, "%Y-%m-%d") date = datetime.strptime(date_str, "%Y-%m-%d")
date_time = datetime(date.year, date.month, date.day, int(hour_str), int(minute_str)) date_time = datetime(
date.year, date.month, date.day, int(hour_str), int(minute_str)
)
self.data = berlin_tz.localize(date_time) self.data = berlin_tz.localize(date_time)
except: except Exception:
raise ValueError('Not a valid datetime value. Looking for YYYY-MM-DD HH:mm.') raise ValueError(
"Not a valid datetime value. Looking for YYYY-MM-DD HH:mm."
)
class CustomDateWidget: class CustomDateWidget:
def __call__(self, field, **kwargs): def __call__(self, field, **kwargs):
id = kwargs.pop('id', field.id) id = kwargs.pop("id", field.id)
date = '' date = ""
if field.data: if field.data:
date_value = to_user_timezone(field.data) date_value = to_user_timezone(field.data)
date = date_value.strftime("%Y-%m-%d") date = date_value.strftime("%Y-%m-%d")
@ -63,6 +82,7 @@ class CustomDateWidget:
date_params = html_params(name=field.name, id=id, value=date, **kwargs) date_params = html_params(name=field.name, id=id, value=date, **kwargs)
return HTMLString('<input type="text" {}/>'.format(date_params)) return HTMLString('<input type="text" {}/>'.format(date_params))
class CustomDateField(DateTimeField): class CustomDateField(DateTimeField):
widget = CustomDateWidget() widget = CustomDateWidget()
@ -76,8 +96,9 @@ class CustomDateField(DateTimeField):
date = datetime.strptime(date_str, "%Y-%m-%d") date = datetime.strptime(date_str, "%Y-%m-%d")
self.data = berlin_tz.localize(date) self.data = berlin_tz.localize(date)
except: except Exception:
raise ValueError('Not a valid date value. Looking for YYYY-MM-DD.') raise ValueError("Not a valid date value. Looking for YYYY-MM-DD.")
def try_to_int(value): def try_to_int(value):
if isinstance(value, int): if isinstance(value, int):
@ -91,15 +112,25 @@ def try_to_int(value):
return value return value
class TagSelectField(SelectField):
def __init__(self, label=None, validators=None, coerce=try_to_int, choices=None, validate_choice=True, **kwargs): class TagSelectField(SelectField):
super(TagSelectField, self).__init__(label, validators, coerce, choices, validate_choice, **kwargs) def __init__(
self,
label=None,
validators=None,
coerce=try_to_int,
choices=None,
validate_choice=True,
**kwargs
):
super(TagSelectField, self).__init__(
label, validators, coerce, choices, validate_choice, **kwargs
)
def pre_validate(self, form): def pre_validate(self, form):
if self.is_free_text(): if self.is_free_text():
if not self.data or not self.data.strip(): if not self.data or not self.data.strip():
raise StopValidation(gettext('This field is required')) raise StopValidation(gettext("This field is required"))
else: else:
super(TagSelectField, self).pre_validate(form) super(TagSelectField, self).pre_validate(form)

View File

@ -1,32 +1,35 @@
from project import app, babel from project import app, babel
from flask_babelex import gettext
from flask import request from flask import request
@babel.localeselector @babel.localeselector
def get_locale(): def get_locale():
return request.accept_languages.best_match(app.config['LANGUAGES']) return request.accept_languages.best_match(app.config["LANGUAGES"])
def print_dynamic_texts(): def print_dynamic_texts():
gettext('Event_Art') gettext("Event_Art")
gettext('Event_Book') gettext("Event_Book")
gettext('Event_Movie') gettext("Event_Movie")
gettext('Event_Family') gettext("Event_Family")
gettext('Event_Festival') gettext("Event_Festival")
gettext('Event_Religious') gettext("Event_Religious")
gettext('Event_Shopping') gettext("Event_Shopping")
gettext('Event_Comedy') gettext("Event_Comedy")
gettext('Event_Music') gettext("Event_Music")
gettext('Event_Dance') gettext("Event_Dance")
gettext('Event_Nightlife') gettext("Event_Nightlife")
gettext('Event_Theater') gettext("Event_Theater")
gettext('Event_Dining') gettext("Event_Dining")
gettext('Event_Conference') gettext("Event_Conference")
gettext('Event_Meetup') gettext("Event_Meetup")
gettext('Event_Fitness') gettext("Event_Fitness")
gettext('Event_Sports') gettext("Event_Sports")
gettext('Event_Other') gettext("Event_Other")
gettext('Typical Age range') gettext("Typical Age range")
gettext('Administrator') gettext("Administrator")
gettext('Event expert') gettext("Event expert")
gettext('EventReviewStatus.inbox') gettext("EventReviewStatus.inbox")
gettext('EventReviewStatus.verified') gettext("EventReviewStatus.verified")
gettext('EventReviewStatus.rejected') gettext("EventReviewStatus.rejected")

View File

@ -3,6 +3,7 @@ from project.services.user import upsert_user_role, add_roles_to_user
from project.services.admin_unit import upsert_admin_unit_member_role from project.services.admin_unit import upsert_admin_unit_member_role
from project.models import Location from project.models import Location
@app.before_first_request @app.before_first_request
def create_initial_data(): def create_initial_data():
admin_permissions = [ admin_permissions = [
@ -10,7 +11,8 @@ def create_initial_data():
"admin_unit.members:invite", "admin_unit.members:invite",
"admin_unit.members:read", "admin_unit.members:read",
"admin_unit.members:update", "admin_unit.members:update",
"admin_unit.members:delete"] "admin_unit.members:delete",
]
event_permissions = [ event_permissions = [
"event:verify", "event:verify",
"event:create", "event:create",
@ -31,15 +33,16 @@ def create_initial_data():
"reference_request:read", "reference_request:read",
"reference_request:update", "reference_request:update",
"reference_request:delete", "reference_request:delete",
"reference_request:verify"] "reference_request:verify",
]
upsert_admin_unit_member_role('admin', 'Administrator', admin_permissions) upsert_admin_unit_member_role("admin", "Administrator", admin_permissions)
upsert_admin_unit_member_role('event_verifier', 'Event expert', event_permissions) upsert_admin_unit_member_role("event_verifier", "Event expert", event_permissions)
upsert_user_role('admin', 'Administrator', admin_permissions) upsert_user_role("admin", "Administrator", admin_permissions)
upsert_user_role('event_verifier', 'Event expert', event_permissions) upsert_user_role("event_verifier", "Event expert", event_permissions)
add_roles_to_user('grams.daniel@gmail.com', ['admin', 'event_verifier']) add_roles_to_user("grams.daniel@gmail.com", ["admin", "event_verifier"])
Location.update_coordinates() Location.update_coordinates()
db.session.commit() db.session.commit()

View File

@ -3,31 +3,37 @@ from project.utils import get_event_category_name, get_localized_enum_name
from urllib.parse import quote_plus from urllib.parse import quote_plus
import os import os
def env_override(value, key):
return os.getenv(key, value)
app.jinja_env.filters['event_category_name'] = lambda u: get_event_category_name(u) def env_override(value, key):
app.jinja_env.filters['loc_enum'] = lambda u: get_localized_enum_name(u) return os.getenv(key, value)
app.jinja_env.filters['env_override'] = env_override
app.jinja_env.filters['quote_plus'] = lambda u: quote_plus(u)
app.jinja_env.filters["event_category_name"] = lambda u: get_event_category_name(u)
app.jinja_env.filters["loc_enum"] = lambda u: get_localized_enum_name(u)
app.jinja_env.filters["env_override"] = env_override
app.jinja_env.filters["quote_plus"] = lambda u: quote_plus(u)
@app.context_processor @app.context_processor
def get_manage_menu_options_context_processor(): def get_manage_menu_options_context_processor():
def get_manage_menu_options(admin_unit):
from project.access import has_access
from project.services.event_suggestion import get_event_reviews_badge_query
from project.services.reference import (
get_reference_requests_incoming_badge_query,
)
def get_manage_menu_options(admin_unit): reviews_badge = 0
from project.access import has_access reference_requests_incoming_badge = get_reference_requests_incoming_badge_query(
from project.services.event_suggestion import get_event_reviews_badge_query admin_unit
from project.services.reference import get_reference_requests_incoming_badge_query ).count()
reviews_badge = 0 if has_access(admin_unit, "event:verify"):
reference_requests_incoming_badge = get_reference_requests_incoming_badge_query(admin_unit).count() reviews_badge = get_event_reviews_badge_query(admin_unit).count()
if has_access(admin_unit, 'event:verify'): return {
reviews_badge = get_event_reviews_badge_query(admin_unit).count() "reviews_badge": reviews_badge,
"reference_requests_incoming_badge": reference_requests_incoming_badge,
}
return { return dict(get_manage_menu_options=get_manage_menu_options)
'reviews_badge': reviews_badge,
'reference_requests_incoming_badge': reference_requests_incoming_badge
}
return dict(get_manage_menu_options=get_manage_menu_options)

View File

@ -5,16 +5,17 @@ from flask import url_for
from project.models import EventAttendanceMode, EventStatus from project.models import EventAttendanceMode, EventStatus
import pytz import pytz
berlin_tz = pytz.timezone('Europe/Berlin') berlin_tz = pytz.timezone("Europe/Berlin")
# subclass JSONEncoder
class DateTimeEncoder(JSONEncoder): class DateTimeEncoder(JSONEncoder):
#Override the default method # Override the default method
def default(self, obj): def default(self, obj):
if isinstance(obj, (datetime.date, datetime.datetime)): if isinstance(obj, (datetime.date, datetime.datetime)):
return (obj.astimezone(berlin_tz)).isoformat() return (obj.astimezone(berlin_tz)).isoformat()
if isinstance(obj, decimal.Decimal): if isinstance(obj, decimal.Decimal):
return float(obj) return float(obj)
def get_sd_for_admin_unit(admin_unit): def get_sd_for_admin_unit(admin_unit):
result = {} result = {}
@ -27,6 +28,7 @@ def get_sd_for_admin_unit(admin_unit):
return result return result
def get_sd_for_organizer_organization(organizer): def get_sd_for_organizer_organization(organizer):
result = {} result = {}
result["@type"] = "Organization" result["@type"] = "Organization"
@ -46,9 +48,11 @@ def get_sd_for_organizer_organization(organizer):
return result return result
def get_sd_for_organizer(organizer): def get_sd_for_organizer(organizer):
return get_sd_for_organizer_organization(organizer) return get_sd_for_organizer_organization(organizer)
def get_sd_for_location(location): def get_sd_for_location(location):
result = {} result = {}
result["@type"] = "PostalAddress" result["@type"] = "PostalAddress"
@ -63,6 +67,7 @@ def get_sd_for_location(location):
return result return result
def get_sd_for_geo(location): def get_sd_for_geo(location):
result = {} result = {}
result["@type"] = "GeoCoordinates" result["@type"] = "GeoCoordinates"
@ -70,6 +75,7 @@ def get_sd_for_geo(location):
result["longitude"] = location.longitude result["longitude"] = location.longitude
return result return result
def get_sd_for_place(place, use_ref=True): def get_sd_for_place(place, use_ref=True):
result = {} result = {}
result["@type"] = "Place" result["@type"] = "Place"
@ -82,13 +88,14 @@ def get_sd_for_place(place, use_ref=True):
result["geo"] = get_sd_for_geo(place.location) result["geo"] = get_sd_for_geo(place.location)
if place.photo_id: if place.photo_id:
result["photo"] = url_for('image', id=place.photo_id) result["photo"] = url_for("image", id=place.photo_id)
if place.url: if place.url:
result["url"] = place.url result["url"] = place.url
return result return result
def get_sd_for_event_date(event_date): def get_sd_for_event_date(event_date):
event = event_date.event event = event_date.event
@ -101,7 +108,7 @@ def get_sd_for_event_date(event_date):
result["startDate"] = event_date.start result["startDate"] = event_date.start
url_list = list() url_list = list()
url_list.append(url_for('event_date', id=event_date.id)) url_list.append(url_for("event_date", id=event_date.id))
if event.external_link: if event.external_link:
url_list.append(event.external_link) url_list.append(event.external_link)
@ -157,6 +164,6 @@ def get_sd_for_event_date(event_date):
result["eventStatus"] = "EventRescheduled" result["eventStatus"] = "EventRescheduled"
if event.photo_id: if event.photo_id:
result["image"] = url_for('image', id=event.photo_id) result["image"] = url_for("image", id=event.photo_id)
return result return result

View File

@ -3,9 +3,19 @@ from sqlalchemy.ext.declarative import declared_attr
from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import relationship, backref, deferred from sqlalchemy.orm import relationship, backref, deferred
from sqlalchemy.schema import CheckConstraint from sqlalchemy.schema import CheckConstraint
from sqlalchemy.types import TypeDecorator
from sqlalchemy.event import listens_for from sqlalchemy.event import listens_for
from sqlalchemy import UniqueConstraint, Boolean, DateTime, Column, Integer, String, ForeignKey, Unicode, UnicodeText, Numeric, LargeBinary from sqlalchemy import (
UniqueConstraint,
Boolean,
DateTime,
Column,
Integer,
String,
ForeignKey,
Unicode,
UnicodeText,
Numeric,
)
from sqlalchemy_utils import ColorType from sqlalchemy_utils import ColorType
from flask_security import UserMixin, RoleMixin from flask_security import UserMixin, RoleMixin
from flask_dance.consumer.storage.sqla import OAuthConsumerMixin from flask_dance.consumer.storage.sqla import OAuthConsumerMixin
@ -15,23 +25,26 @@ from project.dbtypes import IntegerEnum
from geoalchemy2 import Geometry from geoalchemy2 import Geometry
from sqlalchemy import and_ from sqlalchemy import and_
### Base # Base
class TrackableMixin(object): class TrackableMixin(object):
created_at = Column(DateTime, default=datetime.datetime.utcnow) created_at = Column(DateTime, default=datetime.datetime.utcnow)
@declared_attr @declared_attr
def created_by_id(cls): def created_by_id(cls):
return Column('created_by_id', ForeignKey('user.id')) return Column("created_by_id", ForeignKey("user.id"))
@declared_attr @declared_attr
def created_by(cls): def created_by(cls):
return relationship("User") return relationship("User")
### Multi purpose
# Multi purpose
class Image(db.Model, TrackableMixin): class Image(db.Model, TrackableMixin):
__tablename__ = 'image' __tablename__ = "image"
id = Column(Integer(), primary_key=True) id = Column(Integer(), primary_key=True)
data = deferred(db.Column(db.LargeBinary)) data = deferred(db.Column(db.LargeBinary))
encoding_format = Column(String(80)) encoding_format = Column(String(80))
@ -40,24 +53,28 @@ class Image(db.Model, TrackableMixin):
def is_empty(self): def is_empty(self):
return not self.data return not self.data
### User
# User
class RolesUsers(db.Model): class RolesUsers(db.Model):
__tablename__ = 'roles_users' __tablename__ = "roles_users"
id = Column(Integer(), primary_key=True) id = Column(Integer(), primary_key=True)
user_id = Column('user_id', Integer(), ForeignKey('user.id')) user_id = Column("user_id", Integer(), ForeignKey("user.id"))
role_id = Column('role_id', Integer(), ForeignKey('role.id')) role_id = Column("role_id", Integer(), ForeignKey("role.id"))
class Role(db.Model, RoleMixin): class Role(db.Model, RoleMixin):
__tablename__ = 'role' __tablename__ = "role"
id = Column(Integer(), primary_key=True) id = Column(Integer(), primary_key=True)
name = Column(String(80), unique=True) name = Column(String(80), unique=True)
title = Column(Unicode(255)) title = Column(Unicode(255))
description = Column(String(255)) description = Column(String(255))
permissions = Column(UnicodeText()) permissions = Column(UnicodeText())
class User(db.Model, UserMixin): class User(db.Model, UserMixin):
__tablename__ = 'user' __tablename__ = "user"
id = Column(Integer, primary_key=True) id = Column(Integer, primary_key=True)
email = Column(String(255), unique=True) email = Column(String(255), unique=True)
username = Column(String(255)) username = Column(String(255))
@ -70,63 +87,76 @@ class User(db.Model, UserMixin):
active = Column(Boolean()) active = Column(Boolean())
fs_uniquifier = Column(String(255)) fs_uniquifier = Column(String(255))
confirmed_at = Column(DateTime()) confirmed_at = Column(DateTime())
roles = relationship('Role', secondary='roles_users', roles = relationship(
backref=backref('users', lazy='dynamic')) "Role", secondary="roles_users", backref=backref("users", lazy="dynamic")
)
class OAuth(OAuthConsumerMixin, db.Model): class OAuth(OAuthConsumerMixin, db.Model):
provider_user_id = Column(String(256), unique=True, nullable=False) provider_user_id = Column(String(256), unique=True, nullable=False)
user_id = Column(Integer(), ForeignKey('user.id'), nullable=False) user_id = Column(Integer(), ForeignKey("user.id"), nullable=False)
user = db.relationship('User') user = db.relationship("User")
# Admin Unit
### Admin Unit
class AdminUnitMemberRolesMembers(db.Model): class AdminUnitMemberRolesMembers(db.Model):
__tablename__ = 'adminunitmemberroles_members' __tablename__ = "adminunitmemberroles_members"
id = Column(Integer(), primary_key=True) id = Column(Integer(), primary_key=True)
member_id = Column('member_id', Integer(), ForeignKey('adminunitmember.id')) member_id = Column("member_id", Integer(), ForeignKey("adminunitmember.id"))
role_id = Column('role_id', Integer(), ForeignKey('adminunitmemberrole.id')) role_id = Column("role_id", Integer(), ForeignKey("adminunitmemberrole.id"))
class AdminUnitMemberRole(db.Model, RoleMixin): class AdminUnitMemberRole(db.Model, RoleMixin):
__tablename__ = 'adminunitmemberrole' __tablename__ = "adminunitmemberrole"
id = Column(Integer(), primary_key=True) id = Column(Integer(), primary_key=True)
name = Column(String(80), unique=True) name = Column(String(80), unique=True)
title = Column(Unicode(255)) title = Column(Unicode(255))
description = Column(String(255)) description = Column(String(255))
permissions = Column(UnicodeText()) permissions = Column(UnicodeText())
class AdminUnitMember(db.Model): class AdminUnitMember(db.Model):
__tablename__ = 'adminunitmember' __tablename__ = "adminunitmember"
id = Column(Integer(), primary_key=True) id = Column(Integer(), primary_key=True)
admin_unit_id = db.Column(db.Integer, db.ForeignKey('adminunit.id'), nullable=False) 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_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False)
user = db.relationship('User', backref=db.backref('adminunitmembers', lazy=True)) user = db.relationship("User", backref=db.backref("adminunitmembers", lazy=True))
roles = relationship('AdminUnitMemberRole', secondary='adminunitmemberroles_members', roles = relationship(
order_by="AdminUnitMemberRole.id", "AdminUnitMemberRole",
backref=backref('members', lazy='dynamic')) secondary="adminunitmemberroles_members",
order_by="AdminUnitMemberRole.id",
backref=backref("members", lazy="dynamic"),
)
class AdminUnitMemberInvitation(db.Model): class AdminUnitMemberInvitation(db.Model):
__tablename__ = 'adminunitmemberinvitation' __tablename__ = "adminunitmemberinvitation"
__table_args__ = ( __table_args__ = (UniqueConstraint("email", "admin_unit_id"),)
UniqueConstraint('email', 'admin_unit_id'),
)
id = Column(Integer(), primary_key=True) id = Column(Integer(), primary_key=True)
admin_unit_id = db.Column(db.Integer, db.ForeignKey('adminunit.id'), nullable=False) admin_unit_id = db.Column(db.Integer, db.ForeignKey("adminunit.id"), nullable=False)
email = Column(String(255)) email = Column(String(255))
roles = Column(UnicodeText()) roles = Column(UnicodeText())
class AdminUnit(db.Model, TrackableMixin): class AdminUnit(db.Model, TrackableMixin):
__tablename__ = 'adminunit' __tablename__ = "adminunit"
id = Column(Integer(), primary_key=True) id = Column(Integer(), primary_key=True)
name = Column(Unicode(255), unique=True) name = Column(Unicode(255), unique=True)
short_name = Column(Unicode(100), unique=True) short_name = Column(Unicode(100), unique=True)
members = relationship('AdminUnitMember', backref=backref('adminunit', lazy=True)) members = relationship("AdminUnitMember", backref=backref("adminunit", lazy=True))
invitations = relationship('AdminUnitMemberInvitation', backref=backref('adminunit', lazy=True)) invitations = relationship(
event_organizers = relationship('EventOrganizer', backref=backref('adminunit', lazy=True)) "AdminUnitMemberInvitation", backref=backref("adminunit", lazy=True)
event_places = relationship('EventPlace', backref=backref('adminunit', lazy=True)) )
location_id = db.Column(db.Integer, db.ForeignKey('location.id')) event_organizers = relationship(
location = db.relationship('Location') "EventOrganizer", backref=backref("adminunit", lazy=True)
logo_id = db.Column(db.Integer, db.ForeignKey('image.id')) )
logo = db.relationship('Image', uselist=False) 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)) url = Column(String(255))
email = Column(Unicode(255)) email = Column(Unicode(255))
phone = Column(Unicode(255)) phone = Column(Unicode(255))
@ -136,95 +166,113 @@ class AdminUnit(db.Model, TrackableMixin):
widget_primary_color = Column(ColorType) widget_primary_color = Column(ColorType)
widget_link_color = Column(ColorType) widget_link_color = Column(ColorType)
@listens_for(AdminUnit, 'before_insert')
@listens_for(AdminUnit, 'before_update') @listens_for(AdminUnit, "before_insert")
@listens_for(AdminUnit, "before_update")
def purge_admin_unit(mapper, connect, self): def purge_admin_unit(mapper, connect, self):
if self.logo and self.logo.is_empty(): if self.logo and self.logo.is_empty():
self.logo_id = None self.logo_id = None
# Universal Types # Universal Types
class Location(db.Model, TrackableMixin): class Location(db.Model, TrackableMixin):
__tablename__ = 'location' __tablename__ = "location"
id = Column(Integer(), primary_key=True) id = Column(Integer(), primary_key=True)
street = Column(Unicode(255)) street = Column(Unicode(255))
postalCode = Column(Unicode(255)) postalCode = Column(Unicode(255))
city = Column(Unicode(255)) city = Column(Unicode(255))
state = Column(Unicode(255)) state = Column(Unicode(255))
country = Column(Unicode(255)) country = Column(Unicode(255))
latitude = Column(Numeric(18,16)) latitude = Column(Numeric(18, 16))
longitude = Column(Numeric(19,16)) longitude = Column(Numeric(19, 16))
coordinate = Column(Geometry(geometry_type="POINT")) coordinate = Column(Geometry(geometry_type="POINT"))
def is_empty(self): def is_empty(self):
return (not self.street return (
not self.street
and not self.postalCode and not self.postalCode
and not self.city and not self.city
and not self.state and not self.state
and not self.country and not self.country
and not self.latitude and not self.latitude
and not self.longitude) and not self.longitude
)
def update_coordinate(self): def update_coordinate(self):
if self.latitude and self.longitude: if self.latitude and self.longitude:
point = 'POINT({} {})'.format(self.longitude, self.latitude) point = "POINT({} {})".format(self.longitude, self.latitude)
self.coordinate = point self.coordinate = point
else: else:
self.coordinate = None self.coordinate = None
@classmethod @classmethod
def update_coordinates(cls): def update_coordinates(cls):
locations = Location.query.filter(and_(Location.latitude != None, Location.latitude != 0, Location.coordinate == None)).all() locations = Location.query.filter(
and_(
Location.latitude is not None,
Location.latitude != 0,
Location.coordinate is None,
)
).all()
for location in locations: for location in locations:
location.update_coordinate() location.update_coordinate()
db.session.commit() db.session.commit()
@listens_for(Location, 'before_insert')
@listens_for(Location, 'before_update') @listens_for(Location, "before_insert")
@listens_for(Location, "before_update")
def update_location_coordinate(mapper, connect, self): def update_location_coordinate(mapper, connect, self):
self.update_coordinate() self.update_coordinate()
# Events # Events
class EventPlace(db.Model, TrackableMixin): class EventPlace(db.Model, TrackableMixin):
__tablename__ = 'eventplace' __tablename__ = "eventplace"
id = Column(Integer(), primary_key=True) id = Column(Integer(), primary_key=True)
name = Column(Unicode(255), nullable=False) name = Column(Unicode(255), nullable=False)
location_id = db.Column(db.Integer, db.ForeignKey('location.id')) location_id = db.Column(db.Integer, db.ForeignKey("location.id"))
location = db.relationship('Location', uselist=False) location = db.relationship("Location", uselist=False)
photo_id = db.Column(db.Integer, db.ForeignKey('image.id')) photo_id = db.Column(db.Integer, db.ForeignKey("image.id"))
photo = db.relationship('Image', uselist=False) photo = db.relationship("Image", uselist=False)
url = Column(String(255)) url = Column(String(255))
description = Column(UnicodeText()) description = Column(UnicodeText())
admin_unit_id = db.Column(db.Integer, db.ForeignKey('adminunit.id'), nullable=True) admin_unit_id = db.Column(db.Integer, db.ForeignKey("adminunit.id"), nullable=True)
def is_empty(self): def is_empty(self):
return (not self.name) return not self.name
@listens_for(EventPlace, 'before_insert')
@listens_for(EventPlace, 'before_update') @listens_for(EventPlace, "before_insert")
@listens_for(EventPlace, "before_update")
def purge_event_place(mapper, connect, self): def purge_event_place(mapper, connect, self):
if self.location and self.location.is_empty(): if self.location and self.location.is_empty():
self.location_id = None self.location_id = None
if self.photo and self.photo.is_empty(): if self.photo and self.photo.is_empty():
self.photo_id = None self.photo_id = None
class EventCategory(db.Model): class EventCategory(db.Model):
__tablename__ = 'eventcategory' __tablename__ = "eventcategory"
id = Column(Integer(), primary_key=True) id = Column(Integer(), primary_key=True)
name = Column(Unicode(255), nullable=False, unique=True) name = Column(Unicode(255), nullable=False, unique=True)
class EventTargetGroupOrigin(IntEnum): class EventTargetGroupOrigin(IntEnum):
both = 1 both = 1
tourist = 2 tourist = 2
resident = 3 resident = 3
class EventAttendanceMode(IntEnum): class EventAttendanceMode(IntEnum):
offline = 1 offline = 1
online = 2 online = 2
mixed = 3 mixed = 3
class EventStatus(IntEnum): class EventStatus(IntEnum):
scheduled = 1 scheduled = 1
cancelled = 2 cancelled = 2
@ -232,65 +280,77 @@ class EventStatus(IntEnum):
postponed = 4 postponed = 4
rescheduled = 5 rescheduled = 5
class EventReviewStatus(IntEnum): class EventReviewStatus(IntEnum):
inbox = 1 inbox = 1
verified = 2 verified = 2
rejected = 3 rejected = 3
class EventRejectionReason(IntEnum): class EventRejectionReason(IntEnum):
duplicate = 1 duplicate = 1
untrustworthy = 2 untrustworthy = 2
illegal = 3 illegal = 3
class EventReferenceRequestReviewStatus(IntEnum): class EventReferenceRequestReviewStatus(IntEnum):
inbox = 1 inbox = 1
verified = 2 verified = 2
rejected = 3 rejected = 3
class EventReferenceRequestRejectionReason(IntEnum): class EventReferenceRequestRejectionReason(IntEnum):
duplicate = 1 duplicate = 1
untrustworthy = 2 untrustworthy = 2
illegal = 3 illegal = 3
irrelevant = 4 irrelevant = 4
class EventOrganizer(db.Model, TrackableMixin): class EventOrganizer(db.Model, TrackableMixin):
__tablename__ = 'eventorganizer' __tablename__ = "eventorganizer"
__table_args__ = (UniqueConstraint('name', 'admin_unit_id'),) __table_args__ = (UniqueConstraint("name", "admin_unit_id"),)
id = Column(Integer(), primary_key=True) id = Column(Integer(), primary_key=True)
name = Column(Unicode(255), nullable=False) name = Column(Unicode(255), nullable=False)
url = Column(String(255)) url = Column(String(255))
email = Column(Unicode(255)) email = Column(Unicode(255))
phone = Column(Unicode(255)) phone = Column(Unicode(255))
fax = Column(Unicode(255)) fax = Column(Unicode(255))
location_id = db.Column(db.Integer, db.ForeignKey('location.id')) location_id = db.Column(db.Integer, db.ForeignKey("location.id"))
location = db.relationship('Location') location = db.relationship("Location")
logo_id = db.Column(db.Integer, db.ForeignKey('image.id')) logo_id = db.Column(db.Integer, db.ForeignKey("image.id"))
logo = db.relationship('Image', uselist=False) logo = db.relationship("Image", uselist=False)
admin_unit_id = db.Column(db.Integer, db.ForeignKey('adminunit.id'), nullable=True) admin_unit_id = db.Column(db.Integer, db.ForeignKey("adminunit.id"), nullable=True)
def is_empty(self): def is_empty(self):
return not self.name return not self.name
@listens_for(EventOrganizer, 'before_insert')
@listens_for(EventOrganizer, 'before_update') @listens_for(EventOrganizer, "before_insert")
@listens_for(EventOrganizer, "before_update")
def purge_event_organizer(mapper, connect, self): def purge_event_organizer(mapper, connect, self):
if self.logo and self.logo.is_empty(): if self.logo and self.logo.is_empty():
self.logo_id = None self.logo_id = None
class EventReference(db.Model, TrackableMixin): class EventReference(db.Model, TrackableMixin):
__tablename__ = 'eventreference' __tablename__ = "eventreference"
id = Column(Integer(), primary_key=True) id = Column(Integer(), primary_key=True)
event_id = db.Column(db.Integer, db.ForeignKey('event.id'), nullable=False) 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_id = db.Column(db.Integer, db.ForeignKey("adminunit.id"), nullable=False)
admin_unit = db.relationship('AdminUnit', backref=db.backref('references', lazy=True)) admin_unit = db.relationship(
"AdminUnit", backref=db.backref("references", lazy=True)
)
rating = Column(Integer()) rating = Column(Integer())
class EventReferenceRequest(db.Model, TrackableMixin): class EventReferenceRequest(db.Model, TrackableMixin):
__tablename__ = 'eventreferencerequest' __tablename__ = "eventreferencerequest"
id = Column(Integer(), primary_key=True) id = Column(Integer(), primary_key=True)
event_id = db.Column(db.Integer, db.ForeignKey('event.id'), nullable=False) 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_id = db.Column(db.Integer, db.ForeignKey("adminunit.id"), nullable=False)
admin_unit = db.relationship('AdminUnit', backref=db.backref('reference_requests', lazy=True)) admin_unit = db.relationship(
"AdminUnit", backref=db.backref("reference_requests", lazy=True)
)
review_status = Column(IntegerEnum(EventReferenceRequestReviewStatus)) review_status = Column(IntegerEnum(EventReferenceRequestReviewStatus))
rejection_reason = Column(IntegerEnum(EventReferenceRequestRejectionReason)) rejection_reason = Column(IntegerEnum(EventReferenceRequestRejectionReason))
@ -298,12 +358,13 @@ class EventReferenceRequest(db.Model, TrackableMixin):
def verified(self): def verified(self):
return self.review_status == EventReferenceRequestReviewStatus.verified return self.review_status == EventReferenceRequestReviewStatus.verified
class EventSuggestion(db.Model, TrackableMixin): class EventSuggestion(db.Model, TrackableMixin):
__tablename__ = 'eventsuggestion' __tablename__ = "eventsuggestion"
__table_args__ = ( __table_args__ = (
CheckConstraint('NOT(event_place_id IS NULL AND event_place_text IS NULL)'), CheckConstraint("NOT(event_place_id IS NULL AND event_place_text IS NULL)"),
CheckConstraint('NOT(organizer_id IS NULL AND organizer_text IS NULL)'), CheckConstraint("NOT(organizer_id IS NULL AND organizer_text IS NULL)"),
) )
id = Column(Integer(), primary_key=True) id = Column(Integer(), primary_key=True)
name = Column(Unicode(255), nullable=False) name = Column(Unicode(255), nullable=False)
@ -318,29 +379,38 @@ class EventSuggestion(db.Model, TrackableMixin):
contact_phone = Column(Unicode(255)) contact_phone = Column(Unicode(255))
contact_email_notice = Column(Boolean()) contact_email_notice = Column(Boolean())
admin_unit_id = db.Column(db.Integer, db.ForeignKey('adminunit.id'), nullable=False) admin_unit_id = db.Column(db.Integer, db.ForeignKey("adminunit.id"), nullable=False)
admin_unit = db.relationship('AdminUnit', backref=db.backref('eventsuggestions', lazy=True)) admin_unit = db.relationship(
"AdminUnit", backref=db.backref("eventsuggestions", lazy=True)
)
event_place_id = db.Column(db.Integer, db.ForeignKey('eventplace.id'), nullable=True) event_place_id = db.Column(
event_place = db.relationship('EventPlace', uselist=False) db.Integer, db.ForeignKey("eventplace.id"), nullable=True
)
event_place = db.relationship("EventPlace", uselist=False)
event_place_text = Column(Unicode(255), nullable=True) event_place_text = Column(Unicode(255), nullable=True)
organizer_id = db.Column(db.Integer, db.ForeignKey('eventorganizer.id'), nullable=True) organizer_id = db.Column(
organizer = db.relationship('EventOrganizer', uselist=False) db.Integer, db.ForeignKey("eventorganizer.id"), nullable=True
)
organizer = db.relationship("EventOrganizer", uselist=False)
organizer_text = Column(Unicode(255), nullable=True) organizer_text = Column(Unicode(255), nullable=True)
photo_id = db.Column(db.Integer, db.ForeignKey('image.id')) photo_id = db.Column(db.Integer, db.ForeignKey("image.id"))
photo = db.relationship('Image', uselist=False) photo = db.relationship("Image", uselist=False)
event_id = db.Column(db.Integer, db.ForeignKey('event.id', ondelete='SET NULL'), nullable=True) event_id = db.Column(
event = db.relationship('Event', uselist=False) db.Integer, db.ForeignKey("event.id", ondelete="SET NULL"), nullable=True
)
event = db.relationship("Event", uselist=False)
@hybrid_property @hybrid_property
def verified(self): def verified(self):
return self.review_status == EventReviewStatus.verified return self.review_status == EventReviewStatus.verified
@listens_for(EventSuggestion, 'before_insert')
@listens_for(EventSuggestion, 'before_update') @listens_for(EventSuggestion, "before_insert")
@listens_for(EventSuggestion, "before_update")
def purge_event_suggestion(mapper, connect, self): def purge_event_suggestion(mapper, connect, self):
if self.organizer and self.organizer.is_empty(): if self.organizer and self.organizer.is_empty():
self.organizer_id = None self.organizer_id = None
@ -353,23 +423,28 @@ def purge_event_suggestion(mapper, connect, self):
if self.photo and self.photo.is_empty(): if self.photo and self.photo.is_empty():
self.photo_id = None self.photo_id = None
class Event(db.Model, TrackableMixin): class Event(db.Model, TrackableMixin):
__tablename__ = 'event' __tablename__ = "event"
id = Column(Integer(), primary_key=True) id = Column(Integer(), primary_key=True)
admin_unit_id = db.Column(db.Integer, db.ForeignKey('adminunit.id'), nullable=False) admin_unit_id = db.Column(db.Integer, db.ForeignKey("adminunit.id"), nullable=False)
admin_unit = db.relationship('AdminUnit', backref=db.backref('events', lazy=True)) admin_unit = db.relationship("AdminUnit", backref=db.backref("events", lazy=True))
organizer_id = db.Column(db.Integer, db.ForeignKey('eventorganizer.id'), nullable=True) organizer_id = db.Column(
organizer = db.relationship('EventOrganizer', uselist=False) db.Integer, db.ForeignKey("eventorganizer.id"), nullable=True
event_place_id = db.Column(db.Integer, db.ForeignKey('eventplace.id'), nullable=True) )
event_place = db.relationship('EventPlace', uselist=False) 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) name = Column(Unicode(255), nullable=False)
description = Column(UnicodeText(), nullable=False) description = Column(UnicodeText(), nullable=False)
external_link = Column(String(255)) external_link = Column(String(255))
ticket_link = Column(String(255)) ticket_link = Column(String(255))
photo_id = db.Column(db.Integer, db.ForeignKey('image.id')) photo_id = db.Column(db.Integer, db.ForeignKey("image.id"))
photo = db.relationship('Image', uselist=False) photo = db.relationship("Image", uselist=False)
categories = relationship('EventCategory', secondary='event_eventcategories') categories = relationship("EventCategory", secondary="event_eventcategories")
tags = Column(UnicodeText()) tags = Column(UnicodeText())
kid_friendly = Column(Boolean()) kid_friendly = Column(Boolean())
accessible_for_free = Column(Boolean()) accessible_for_free = Column(Boolean())
@ -389,10 +464,20 @@ class Event(db.Model, TrackableMixin):
recurrence_rule = Column(UnicodeText()) recurrence_rule = Column(UnicodeText())
start = db.Column(db.DateTime(timezone=True), nullable=True) start = db.Column(db.DateTime(timezone=True), nullable=True)
end = 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") dates = relationship(
"EventDate", backref=backref("event", lazy=False), cascade="all, delete-orphan"
)
references = relationship('EventReference', backref=backref('event', lazy=False), cascade="all, delete-orphan") references = relationship(
reference_requests = relationship('EventReferenceRequest', backref=backref('event', lazy=False), cascade="all, delete-orphan") "EventReference",
backref=backref("event", lazy=False),
cascade="all, delete-orphan",
)
reference_requests = relationship(
"EventReferenceRequest",
backref=backref("event", lazy=False),
cascade="all, delete-orphan",
)
@hybrid_property @hybrid_property
def category(self): def category(self):
@ -401,8 +486,9 @@ class Event(db.Model, TrackableMixin):
else: else:
return None return None
@listens_for(Event, 'before_insert')
@listens_for(Event, 'before_update') @listens_for(Event, "before_insert")
@listens_for(Event, "before_update")
def purge_event(mapper, connect, self): def purge_event(mapper, connect, self):
if self.organizer and self.organizer.is_empty(): if self.organizer and self.organizer.is_empty():
self.organizer_id = None self.organizer_id = None
@ -411,36 +497,45 @@ def purge_event(mapper, connect, self):
if self.photo and self.photo.is_empty(): if self.photo and self.photo.is_empty():
self.photo_id = None self.photo_id = None
class EventDate(db.Model): class EventDate(db.Model):
__tablename__ = 'eventdate' __tablename__ = "eventdate"
id = Column(Integer(), primary_key=True) id = Column(Integer(), primary_key=True)
event_id = db.Column(db.Integer, db.ForeignKey('event.id'), nullable=False) event_id = db.Column(db.Integer, db.ForeignKey("event.id"), nullable=False)
start = db.Column(db.DateTime(timezone=True), nullable=False) start = db.Column(db.DateTime(timezone=True), nullable=False)
end = db.Column(db.DateTime(timezone=True), nullable=True) end = db.Column(db.DateTime(timezone=True), nullable=True)
class EventEventCategories(db.Model): class EventEventCategories(db.Model):
__tablename__ = 'event_eventcategories' __tablename__ = "event_eventcategories"
id = Column(Integer(), primary_key=True) id = Column(Integer(), primary_key=True)
event_id = db.Column(db.Integer, db.ForeignKey('event.id'), nullable=False) event_id = db.Column(db.Integer, db.ForeignKey("event.id"), nullable=False)
category_id = db.Column(db.Integer, db.ForeignKey('eventcategory.id'), nullable=False) category_id = db.Column(
db.Integer, db.ForeignKey("eventcategory.id"), nullable=False
)
class Analytics(db.Model): class Analytics(db.Model):
__tablename__ = 'analytics' __tablename__ = "analytics"
id = Column(Integer(), primary_key=True) id = Column(Integer(), primary_key=True)
key = Column(Unicode(255)) key = Column(Unicode(255))
value1 = Column(Unicode(255)) value1 = Column(Unicode(255))
value2 = Column(Unicode(255)) value2 = Column(Unicode(255))
created_at = Column(DateTime, default=datetime.datetime.utcnow) created_at = Column(DateTime, default=datetime.datetime.utcnow)
# Deprecated begin # Deprecated begin
class FeaturedEventReviewStatus(IntEnum): class FeaturedEventReviewStatus(IntEnum):
inbox = 1 inbox = 1
verified = 2 verified = 2
rejected = 3 rejected = 3
class FeaturedEventRejectionReason(IntEnum): class FeaturedEventRejectionReason(IntEnum):
duplicate = 1 duplicate = 1
untrustworthy = 2 untrustworthy = 2
illegal = 3 illegal = 3
irrelevant = 4 irrelevant = 4
# Deprecated end # Deprecated end

View File

@ -3,8 +3,7 @@ from flask_security import current_user, login_user
from flask_dance.contrib.google import make_google_blueprint from flask_dance.contrib.google import make_google_blueprint
from flask_dance.consumer import oauth_authorized, oauth_error from flask_dance.consumer import oauth_authorized, oauth_error
from flask_dance.consumer.storage.sqla import SQLAlchemyStorage from flask_dance.consumer.storage.sqla import SQLAlchemyStorage
from sqlalchemy.orm.exc import NoResultFound from project.models import OAuth
from project.models import User, OAuth
from project import db, user_datastore from project import db, user_datastore
from flask_babelex import gettext from flask_babelex import gettext
@ -31,14 +30,16 @@ def google_logged_in(blueprint, token):
user_id = info["id"] user_id = info["id"]
# Find this OAuth token in the database, or create it # Find this OAuth token in the database, or create it
oauth = OAuth.query.filter_by(provider=blueprint.name, provider_user_id=user_id).first() oauth = OAuth.query.filter_by(
provider=blueprint.name, provider_user_id=user_id
).first()
if oauth is None: if oauth is None:
oauth = OAuth(provider=blueprint.name, provider_user_id=user_id, token=token) oauth = OAuth(provider=blueprint.name, provider_user_id=user_id, token=token)
if oauth.user: if oauth.user:
login_user(oauth.user, authn_via=["google"]) login_user(oauth.user, authn_via=["google"])
user_datastore.commit() user_datastore.commit()
flash(gettext("Successfully signed in."), 'success') flash(gettext("Successfully signed in."), "success")
else: else:
# Create a new local user account for this user # Create a new local user account for this user
@ -51,7 +52,7 @@ def google_logged_in(blueprint, token):
# Log in the new local user account # Log in the new local user account
login_user(user, authn_via=["google"]) login_user(user, authn_via=["google"])
user_datastore.commit() user_datastore.commit()
flash(gettext("Successfully signed in."), 'success') flash(gettext("Successfully signed in."), "success")
# Disable Flask-Dance's default behavior for saving the OAuth token # Disable Flask-Dance's default behavior for saving the OAuth token
return False return False

View File

@ -1,23 +1,34 @@
from project import app, db, get_admin_unit, update_event_dates_with_recurrence_rule, upsert_event_category from project import (
db,
get_admin_unit,
update_event_dates_with_recurrence_rule,
upsert_event_category,
)
from pprint import pprint from pprint import pprint
import datetime import datetime
from dateutil import parser, tz
import pytz import pytz
from urllib.request import urlopen, URLError from urllib.request import urlopen
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
import requests
from os import path from os import path
import json import json
import re import re
import unicodedata
import decimal import decimal
from project.models import EventReviewStatus, EventTargetGroupOrigin, Location, Event, EventStatus, EventCategory, EventPlace, EventOrganizer, AdminUnit from project.models import (
from sqlalchemy import and_, or_, not_ EventReviewStatus,
EventTargetGroupOrigin,
Location,
Event,
EventStatus,
EventPlace,
EventOrganizer,
)
from sqlalchemy import and_
berlin_tz = pytz.timezone("Europe/Berlin")
berlin_tz = pytz.timezone('Europe/Berlin')
def scrape(debug): def scrape(debug):
url = 'https://goslar.feripro.de/programm/42/anmeldung/veranstaltungen' url = "https://goslar.feripro.de/programm/42/anmeldung/veranstaltungen"
if debug: if debug:
filename = "tmp/fp.html" filename = "tmp/fp.html"
@ -27,51 +38,61 @@ def scrape(debug):
with open(filename, "wb") as text_file: with open(filename, "wb") as text_file:
text_file.write(response.read()) text_file.write(response.read())
doc = BeautifulSoup(open(filename), 'html.parser') doc = BeautifulSoup(open(filename), "html.parser")
else: else:
response = urlopen(url) response = urlopen(url)
doc = BeautifulSoup(response, 'html.parser') doc = BeautifulSoup(response, "html.parser")
js_assigns_regex = r"(\w*)\s*:\s*JSON\.parse\('(.*)'\)" js_assigns_regex = r"(\w*)\s*:\s*JSON\.parse\('(.*)'\)"
js_assigns = dict() js_assigns = dict()
javascripts = doc.find_all('script') javascripts = doc.find_all("script")
for javascript in javascripts: for javascript in javascripts:
javascript_contents = javascript.contents[0] if len(javascript.contents) > 0 else '' javascript_contents = (
javascript.contents[0] if len(javascript.contents) > 0 else ""
)
if 'window.fp_initial' in javascript_contents: if "window.fp_initial" in javascript_contents:
matches = re.findall(js_assigns_regex, javascript_contents, re.MULTILINE) matches = re.findall(js_assigns_regex, javascript_contents, re.MULTILINE)
for match in matches: for match in matches:
key = match[0] key = match[0]
if not key in ['events']: if key not in ["events"]:
continue continue
json_str = match[1] json_str = match[1]
decoded_json_str = json_str.encode('utf-8').decode('unicode_escape').encode('latin-1').decode('utf-8') decoded_json_str = (
json_str.encode("utf-8")
.decode("unicode_escape")
.encode("latin-1")
.decode("utf-8")
)
value = json.loads(decoded_json_str, strict=False) value = json.loads(decoded_json_str, strict=False)
js_assigns[key] = value js_assigns[key] = value
break break
admin_unit = get_admin_unit('Ferienpass Goslar') admin_unit = get_admin_unit("Ferienpass Goslar")
category = upsert_event_category('Other') category = upsert_event_category("Other")
for js_event in js_assigns['events']: for js_event in js_assigns["events"]:
if not 'event_id' in js_event: if "event_id" not in js_event:
continue continue
event_id = js_event['event_id'] event_id = js_event["event_id"]
if not event_id: if not event_id:
continue continue
try: try:
external_link = url + '#' + str(event_id) external_link = url + "#" + str(event_id)
event = Event.query.filter(Event.external_link == external_link).first() event = Event.query.filter(Event.external_link == external_link).first()
did_create = False did_create = False
# Event # Event
if event is None: if event is None:
if js_event['name'] in ['Entfällt', 'Diese Veranstaltung muss leider ausfallen ...']: if js_event["name"] in [
"Entfällt",
"Diese Veranstaltung muss leider ausfallen ...",
]:
continue continue
event = Event() event = Event()
@ -83,27 +104,46 @@ def scrape(debug):
event.review_status = EventReviewStatus.verified event.review_status = EventReviewStatus.verified
event.rating = 5 event.rating = 5
event.target_group_origin = EventTargetGroupOrigin.resident event.target_group_origin = EventTargetGroupOrigin.resident
event.name = js_event['name'] event.name = js_event["name"]
event.description = js_event['description'] event.description = js_event["description"]
start = parse_date_time_str(js_event['start']) start = parse_date_time_str(js_event["start"])
end = parse_date_time_str(js_event['end']) end = parse_date_time_str(js_event["end"])
update_event_dates_with_recurrence_rule(event, start, end) update_event_dates_with_recurrence_rule(event, start, end)
# Organizer # Organizer
js_organizer = js_event['organizer'] js_organizer = js_event["organizer"]
organizer_name = js_event['name_public'] if js_event['name_public'] else js_organizer['name'] organizer_name = (
organizer_phone = js_event['phone_public'] if js_event['phone_public'] else js_organizer['phone'] js_event["name_public"]
organizer_email = js_event['email_public'] if js_event['email_public'] else js_organizer['email'] if js_event["name_public"]
organizer_url = js_organizer['website'] if js_organizer['website'] else js_organizer['facebook'] else js_organizer["name"]
)
organizer_phone = (
js_event["phone_public"]
if js_event["phone_public"]
else js_organizer["phone"]
)
organizer_email = (
js_event["email_public"]
if js_event["email_public"]
else js_organizer["email"]
)
organizer_url = (
js_organizer["website"]
if js_organizer["website"]
else js_organizer["facebook"]
)
organizer = EventOrganizer.query.filter(and_( organizer = EventOrganizer.query.filter(
EventOrganizer.admin_unit_id == admin_unit.id, and_(
EventOrganizer.name == organizer_name)).first() EventOrganizer.admin_unit_id == admin_unit.id,
EventOrganizer.name == organizer_name,
)
).first()
if organizer is None: if organizer is None:
organizer = EventOrganizer( organizer = EventOrganizer(
admin_unit_id = admin_unit.id, admin_unit_id=admin_unit.id, name=organizer_name
name = organizer_name) )
organizer.phone = organizer_phone organizer.phone = organizer_phone
organizer.email = organizer_email organizer.email = organizer_email
@ -115,16 +155,19 @@ def scrape(debug):
place_description = "" place_description = ""
place_location = None place_location = None
meeting_point = js_event['meeting_point'].replace('\r\n', ', ') meeting_point = js_event["meeting_point"].replace("\r\n", ", ")
if len(meeting_point) > 80: if len(meeting_point) > 80:
place_name = meeting_point[:80] + '...' place_name = meeting_point[:80] + "..."
place_description = meeting_point place_description = meeting_point
else: else:
place_name = meeting_point place_name = meeting_point
if 'meeting_point_latitude' in js_event and 'meeting_point_longitude' in js_event: if (
meeting_point_latitude = js_event['meeting_point_latitude'] "meeting_point_latitude" in js_event
meeting_point_longitude = js_event['meeting_point_longitude'] and "meeting_point_longitude" in js_event
):
meeting_point_latitude = js_event["meeting_point_latitude"]
meeting_point_longitude = js_event["meeting_point_longitude"]
if meeting_point_latitude and meeting_point_longitude: if meeting_point_latitude and meeting_point_longitude:
latitude = decimal.Decimal(meeting_point_latitude) latitude = decimal.Decimal(meeting_point_latitude)
longitude = decimal.Decimal(meeting_point_longitude) longitude = decimal.Decimal(meeting_point_longitude)
@ -133,45 +176,55 @@ def scrape(debug):
place_location.latitude = latitude place_location.latitude = latitude
place_location.longitude = longitude place_location.longitude = longitude
place = EventPlace.query.filter(and_( place = EventPlace.query.filter(
EventPlace.admin_unit_id == admin_unit.id, and_(
EventPlace.organizer_id == organizer.id, EventPlace.admin_unit_id == admin_unit.id,
EventPlace.name == place_name)).first() EventPlace.organizer_id == organizer.id,
EventPlace.name == place_name,
)
).first()
if place is None: if place is None:
place = EventPlace( place = EventPlace(
admin_unit_id = admin_unit.id, admin_unit_id=admin_unit.id,
organizer_id = organizer.id, organizer_id=organizer.id,
name = place_name) name=place_name,
)
place.description = place_description place.description = place_description
place.location = place_location place.location = place_location
event.event_place = place event.event_place = place
# Additional data # Additional data
event.status = EventStatus.cancelled if js_event['canceled'] else EventStatus.scheduled event.status = (
EventStatus.cancelled if js_event["canceled"] else EventStatus.scheduled
)
event.kid_friendly = True event.kid_friendly = True
event.accessible_for_free = js_event['price'] == '0.00' event.accessible_for_free = js_event["price"] == "0.00"
tag_list = js_event['tags'] tag_list = js_event["tags"]
tag_list.append('Ferienpass') tag_list.append("Ferienpass")
event.tags = ','.join(tag_list) event.tags = ",".join(tag_list)
if js_event['min_age']: if js_event["min_age"]:
event.age_from = int(js_event['min_age']) event.age_from = int(js_event["min_age"])
if js_event['max_age']: if js_event["max_age"]:
event.age_to = int(js_event['max_age']) event.age_to = int(js_event["max_age"])
print("%s %s %s %s" % (event.dates[0].start, event.name, organizer.id, organizer.name)) print(
"%s %s %s %s"
% (event.dates[0].start, event.name, organizer.id, organizer.name)
)
if did_create: if did_create:
db.session.add(event) db.session.add(event)
db.session.commit() db.session.commit()
except: except Exception:
print("Exception") print("Exception")
pprint(js_event) pprint(js_event)
def parse_date_time_str(date_time_str): def parse_date_time_str(date_time_str):
if not date_time_str: if not date_time_str:
return None return None
@ -179,5 +232,6 @@ def parse_date_time_str(date_time_str):
date_time = datetime.datetime.fromisoformat(date_time_str) date_time = datetime.datetime.fromisoformat(date_time_str)
return berlin_tz.localize(date_time) return berlin_tz.localize(date_time)
if __name__ == '__main__':
if __name__ == "__main__":
scrape(False) scrape(False)

View File

@ -1,45 +1,50 @@
from project import app, db from project import db
from pprint import pprint from pprint import pprint
import datetime import datetime
from dateutil import parser, tz from urllib import request
import pytz
from urllib import request, parse
from urllib.request import urlopen, URLError
from bs4 import BeautifulSoup
import requests
from os import path from os import path
import json import json
from flask import jsonify
import re
import unicodedata
import decimal import decimal
from project.models import EventReviewStatus, EventTargetGroupOrigin, Location, Event, EventStatus, EventCategory, EventPlace, EventOrganizer, AdminUnit from project.models import (
from sqlalchemy import and_, or_, not_ EventReviewStatus,
from project.dateutils import berlin_tz Location,
Event,
EventStatus,
EventPlace,
EventOrganizer,
)
from sqlalchemy import and_, not_
from project.services.admin_unit import get_admin_unit from project.services.admin_unit import get_admin_unit
from project.services.event import upsert_event_category, update_event_dates_with_recurrence_rule from project.services.event import (
upsert_event_category,
update_event_dates_with_recurrence_rule,
)
admin_unit = get_admin_unit('Harzinfo') admin_unit = get_admin_unit("Harzinfo")
category = upsert_event_category('Other') category = upsert_event_category("Other")
base_url = "https://www.harzinfo.de" base_url = "https://www.harzinfo.de"
url = base_url + "/?ndssearch=fullsearch&no_cache=1&L=0" url = base_url + "/?ndssearch=fullsearch&no_cache=1&L=0"
with open('scrape_hi_req.json') as json_file: with open("scrape_hi_req.json") as json_file:
request_object = json.load(json_file) request_object = json.load(json_file)
with open('scrape_hi_cities.json') as json_file: with open("scrape_hi_cities.json") as json_file:
cities = json.load(json_file) cities = json.load(json_file)
def response_from_url(city): def response_from_url(city):
body = request_object body = request_object
body["searchFilter"]["ndsdestinationdataevent"]["city"] = { str(city['id']): city['short_name'] or city['title'] } body["searchFilter"]["ndsdestinationdataevent"]["city"] = {
req = request.Request(url, data=bytes(json.dumps(body), encoding='utf-8')) str(city["id"]): city["short_name"] or city["title"]
req.add_header('Content-Type', 'application/json') }
req = request.Request(url, data=bytes(json.dumps(body), encoding="utf-8"))
req.add_header("Content-Type", "application/json")
return request.urlopen(req) return request.urlopen(req)
def load_json(debug, city): def load_json(debug, city):
if debug: if debug:
filename = "tmp/hi_%d.html" % (city['id']) filename = "tmp/hi_%d.html" % (city["id"])
if not path.exists(filename): if not path.exists(filename):
response = response_from_url(city) response = response_from_url(city)
@ -52,24 +57,27 @@ def load_json(debug, city):
response = response_from_url(city) response = response_from_url(city)
return json.load(response) return json.load(response)
def parse_date_time_str(date_time_str): def parse_date_time_str(date_time_str):
if not date_time_str: if not date_time_str:
return None return None
return datetime.datetime.fromisoformat(date_time_str + ':00') return datetime.datetime.fromisoformat(date_time_str + ":00")
def scrape(debug, city): def scrape(debug, city):
# Organizer # Organizer
organizer_name = city['short_name'] or city['title'] organizer_name = city["short_name"] or city["title"]
organizer = EventOrganizer.query.filter(and_( organizer = EventOrganizer.query.filter(
EventOrganizer.admin_unit_id == admin_unit.id, and_(
EventOrganizer.name == organizer_name)).first() EventOrganizer.admin_unit_id == admin_unit.id,
EventOrganizer.name == organizer_name,
)
).first()
if organizer is None: if organizer is None:
organizer = EventOrganizer( organizer = EventOrganizer(admin_unit_id=admin_unit.id, name=organizer_name)
admin_unit_id = admin_unit.id,
name = organizer_name)
db.session.add(organizer) db.session.add(organizer)
db.session.commit() db.session.commit()
@ -81,8 +89,13 @@ def scrape(debug, city):
for item in result: for item in result:
try: try:
uid = str(item["uid"]) uid = str(item["uid"])
external_link = base_url + item["link"] + '#' + uid external_link = base_url + item["link"] + "#" + uid
event = Event.query.filter(and_(Event.organizer_id == organizer.id, Event.external_link == external_link)).first() event = Event.query.filter(
and_(
Event.organizer_id == organizer.id,
Event.external_link == external_link,
)
).first()
did_create = False did_create = False
if event is None: if event is None:
@ -100,7 +113,7 @@ def scrape(debug, city):
event.name = item["title"] event.name = item["title"]
event.description = item["title"] event.description = item["title"]
start = parse_date_time_str(item['date']) start = parse_date_time_str(item["date"])
update_event_dates_with_recurrence_rule(event, start, None) update_event_dates_with_recurrence_rule(event, start, None)
# Place # Place
@ -108,9 +121,9 @@ def scrape(debug, city):
place_description = "" place_description = ""
place_location = None place_location = None
if 'latitude' in item and 'longitude' in item: if "latitude" in item and "longitude" in item:
meeting_point_latitude = item['latitude'] meeting_point_latitude = item["latitude"]
meeting_point_longitude = item['longitude'] meeting_point_longitude = item["longitude"]
if meeting_point_latitude and meeting_point_longitude: if meeting_point_latitude and meeting_point_longitude:
latitude = decimal.Decimal(meeting_point_latitude) latitude = decimal.Decimal(meeting_point_latitude)
longitude = decimal.Decimal(meeting_point_longitude) longitude = decimal.Decimal(meeting_point_longitude)
@ -119,74 +132,87 @@ def scrape(debug, city):
place_location.latitude = latitude place_location.latitude = latitude
place_location.longitude = longitude place_location.longitude = longitude
place = EventPlace.query.filter(and_( place = EventPlace.query.filter(
EventPlace.admin_unit_id == admin_unit.id, and_(
EventPlace.organizer_id == organizer.id, EventPlace.admin_unit_id == admin_unit.id,
EventPlace.name == place_name)).first() EventPlace.organizer_id == organizer.id,
EventPlace.name == place_name,
)
).first()
if place is None: if place is None:
place = EventPlace( place = EventPlace(
admin_unit_id = admin_unit.id, admin_unit_id=admin_unit.id,
organizer_id = organizer.id, organizer_id=organizer.id,
name = place_name) name=place_name,
)
place.description = place_description place.description = place_description
place.location = place_location place.location = place_location
event.event_place = place event.event_place = place
# Additional data # Additional data
event.status = EventStatus.cancelled if item['canceled'] else EventStatus.scheduled event.status = (
EventStatus.cancelled if item["canceled"] else EventStatus.scheduled
)
if 'categories' in item: if "categories" in item:
tag_list = list(item['categories'].values()) tag_list = list(item["categories"].values())
if 'Ausstellung/Kunst' in tag_list: if "Ausstellung/Kunst" in tag_list:
event.category = upsert_event_category('Art') event.category = upsert_event_category("Art")
elif 'Comedy' in tag_list: elif "Comedy" in tag_list:
event.category = upsert_event_category('Comedy') event.category = upsert_event_category("Comedy")
elif 'Konzert/Musik' in tag_list: elif "Konzert/Musik" in tag_list:
event.category = upsert_event_category('Music') event.category = upsert_event_category("Music")
elif 'Theater' in tag_list: elif "Theater" in tag_list:
event.category = upsert_event_category('Theater') event.category = upsert_event_category("Theater")
elif 'Genuss/Gourmet' in tag_list: elif "Genuss/Gourmet" in tag_list:
event.category = upsert_event_category('Dining') event.category = upsert_event_category("Dining")
elif 'Gesundheit/Wellness' in tag_list: elif "Gesundheit/Wellness" in tag_list:
event.category = upsert_event_category('Fitness') event.category = upsert_event_category("Fitness")
elif 'Kinder/Jugend' in tag_list: elif "Kinder/Jugend" in tag_list:
event.category = upsert_event_category('Family') event.category = upsert_event_category("Family")
elif 'Markt/Flohmarkt' in tag_list: elif "Markt/Flohmarkt" in tag_list:
event.category = upsert_event_category('Shopping') event.category = upsert_event_category("Shopping")
elif 'Sport' in tag_list: elif "Sport" in tag_list:
event.category = upsert_event_category('Sports') event.category = upsert_event_category("Sports")
elif 'Vortrag/Lesung' in tag_list: elif "Vortrag/Lesung" in tag_list:
event.category = upsert_event_category('Book') event.category = upsert_event_category("Book")
elif 'Kabarett' in tag_list: elif "Kabarett" in tag_list:
event.category = upsert_event_category('Art') event.category = upsert_event_category("Art")
elif 'Musical' in tag_list: elif "Musical" in tag_list:
event.category = upsert_event_category('Theater') event.category = upsert_event_category("Theater")
elif 'Weihnachtsmärkte' in tag_list: elif "Weihnachtsmärkte" in tag_list:
event.category = upsert_event_category('Festival') event.category = upsert_event_category("Festival")
elif 'Stadt- und Volksfeste' in tag_list: elif "Stadt- und Volksfeste" in tag_list:
event.category = upsert_event_category('Festival') event.category = upsert_event_category("Festival")
if 'Kinder/Jugend' in tag_list: if "Kinder/Jugend" in tag_list:
event.kid_friendly = True event.kid_friendly = True
tag_list.append('Harzinfo') tag_list.append("Harzinfo")
event.tags = ','.join(tag_list) event.tags = ",".join(tag_list)
print("%s %s %d" % (event.dates[0].start, event.name, event.rating)) print("%s %s %d" % (event.dates[0].start, event.name, event.rating))
if did_create: if did_create:
db.session.add(event) db.session.add(event)
db.session.commit() db.session.commit()
except: except Exception:
print("Exception") print("Exception")
pprint(item) pprint(item)
Event.query.filter(and_(Event.admin_unit_id == admin_unit.id, Event.organizer_id == organizer.id, not_(Event.id.in_(event_ids)))).delete(synchronize_session='fetch') Event.query.filter(
and_(
Event.admin_unit_id == admin_unit.id,
Event.organizer_id == organizer.id,
not_(Event.id.in_(event_ids)),
)
).delete(synchronize_session="fetch")
db.session.commit() db.session.commit()
if __name__ == '__main__':
if __name__ == "__main__":
for city in cities.values(): for city in cities.values():
scrape(False, city) scrape(False, city)

View File

@ -1,26 +1,29 @@
from project import db from project import db
from project.models import AdminUnit, AdminUnitMember, AdminUnitMemberRole from project.models import AdminUnit, AdminUnitMember, AdminUnitMemberRole
def upsert_admin_unit(unit_name, short_name = None):
admin_unit = AdminUnit.query.filter_by(name = unit_name).first() def upsert_admin_unit(unit_name, short_name=None):
admin_unit = AdminUnit.query.filter_by(name=unit_name).first()
if admin_unit is None: if admin_unit is None:
admin_unit = AdminUnit(name = unit_name) admin_unit = AdminUnit(name=unit_name)
db.session.add(admin_unit) db.session.add(admin_unit)
admin_unit.short_name = short_name admin_unit.short_name = short_name
upsert_org_or_admin_unit_for_admin_unit(admin_unit)
return admin_unit return admin_unit
def get_admin_unit(unit_name): def get_admin_unit(unit_name):
return AdminUnit.query.filter_by(name = unit_name).first() return AdminUnit.query.filter_by(name=unit_name).first()
def get_admin_unit_member_role(role_name): def get_admin_unit_member_role(role_name):
return AdminUnitMemberRole.query.filter_by(name = role_name).first() return AdminUnitMemberRole.query.filter_by(name=role_name).first()
def upsert_admin_unit_member_role(role_name, role_title, permissions): def upsert_admin_unit_member_role(role_name, role_title, permissions):
result = AdminUnitMemberRole.query.filter_by(name = role_name).first() result = AdminUnitMemberRole.query.filter_by(name=role_name).first()
if result is None: if result is None:
result = AdminUnitMemberRole(name = role_name) result = AdminUnitMemberRole(name=role_name)
db.session.add(result) db.session.add(result)
result.title = role_title result.title = role_title
@ -28,25 +31,36 @@ def upsert_admin_unit_member_role(role_name, role_title, permissions):
result.add_permissions(permissions) result.add_permissions(permissions)
return result return result
def add_user_to_admin_unit(user, admin_unit): def add_user_to_admin_unit(user, admin_unit):
result = AdminUnitMember.query.with_parent(admin_unit).filter_by(user_id = user.id).first() result = (
AdminUnitMember.query.with_parent(admin_unit).filter_by(user_id=user.id).first()
)
if result is None: if result is None:
result = AdminUnitMember(user = user, admin_unit_id=admin_unit.id) result = AdminUnitMember(user=user, admin_unit_id=admin_unit.id)
admin_unit.members.append(result) admin_unit.members.append(result)
db.session.add(result) db.session.add(result)
return result return result
def add_user_to_admin_unit_with_roles(user, admin_unit, role_names): def add_user_to_admin_unit_with_roles(user, admin_unit, role_names):
member = add_user_to_admin_unit(user, admin_unit) member = add_user_to_admin_unit(user, admin_unit)
add_roles_to_admin_unit_member(member, role_names) add_roles_to_admin_unit_member(member, role_names)
return member return member
def add_roles_to_admin_unit_member(member, role_names): def add_roles_to_admin_unit_member(member, role_names):
for role_name in role_names: for role_name in role_names:
role = get_admin_unit_member_role(role_name) role = get_admin_unit_member_role(role_name)
add_role_to_admin_unit_member(member, role) add_role_to_admin_unit_member(member, role)
def add_role_to_admin_unit_member(admin_unit_member, role): def add_role_to_admin_unit_member(admin_unit_member, role):
if AdminUnitMemberRole.query.with_parent(admin_unit_member).filter_by(name = role.name).first() is None: if (
AdminUnitMemberRole.query.with_parent(admin_unit_member)
.filter_by(name=role.name)
.first()
is None
):
admin_unit_member.roles.append(role) admin_unit_member.roles.append(role)

View File

@ -1,49 +1,84 @@
from project.models import EventReviewStatus, EventCategory, Event, EventDate, EventReference, EventPlace, Location, EventSuggestion from project import db
from project.dateutils import dates_from_recurrence_rule, today, date_add_time, date_set_end_of_day from project.models import (
from sqlalchemy import and_, or_, not_, func EventCategory,
Event,
EventDate,
EventReference,
EventPlace,
Location,
)
from project.dateutils import (
dates_from_recurrence_rule,
today,
date_add_time,
)
from sqlalchemy import and_, or_, func
from sqlalchemy.sql import extract from sqlalchemy.sql import extract
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
def upsert_event_category(category_name): def upsert_event_category(category_name):
result = EventCategory.query.filter_by(name = category_name).first() result = EventCategory.query.filter_by(name=category_name).first()
if result is None: if result is None:
result = EventCategory(name = category_name) result = EventCategory(name=category_name)
db.session.add(result) db.session.add(result)
return result return result
def fill_event_filter(event_filter, params): def fill_event_filter(event_filter, params):
if params.keyword: if params.keyword:
like_keyword = '%' + params.keyword + '%' like_keyword = "%" + params.keyword + "%"
event_filter = and_(event_filter, or_(Event.name.ilike(like_keyword), Event.description.ilike(like_keyword), Event.tags.ilike(like_keyword))) event_filter = and_(
event_filter,
or_(
Event.name.ilike(like_keyword),
Event.description.ilike(like_keyword),
Event.tags.ilike(like_keyword),
),
)
if params.category_id: if params.category_id:
if type(params.category_id) is list: if type(params.category_id) is list:
category_ids = params.category_id category_ids = params.category_id
else: else:
category_ids = [params.category_id] category_ids = [params.category_id]
event_filter = and_(event_filter, Event.categories.any(EventCategory.id.in_(category_ids))) event_filter = and_(
event_filter, Event.categories.any(EventCategory.id.in_(category_ids))
)
if params.organizer_id: if params.organizer_id:
event_filter = and_(event_filter, Event.organizer_id == params.organizer_id) event_filter = and_(event_filter, Event.organizer_id == params.organizer_id)
if params.latitude and params.longitude and params.distance: if params.latitude and params.longitude and params.distance:
point = 'POINT({} {})'.format(params.longitude, params.latitude) point = "POINT({} {})".format(params.longitude, params.latitude)
event_filter = and_(event_filter, func.ST_DistanceSphere(Location.coordinate, point) <= params.distance) event_filter = and_(
event_filter,
func.ST_DistanceSphere(Location.coordinate, point) <= params.distance,
)
return event_filter return event_filter
def get_event_dates_query(params): def get_event_dates_query(params):
event_filter = (1 == 1) event_filter = 1 == 1
date_filter = (EventDate.start >= today) date_filter = EventDate.start >= today
event_filter = fill_event_filter(event_filter, params) event_filter = fill_event_filter(event_filter, params)
if params.admin_unit_id: if params.admin_unit_id:
event_filter = and_(event_filter, or_(Event.admin_unit_id == params.admin_unit_id, Event.references.any(EventReference.admin_unit_id == params.admin_unit_id))) event_filter = and_(
event_filter,
or_(
Event.admin_unit_id == params.admin_unit_id,
Event.references.any(
EventReference.admin_unit_id == params.admin_unit_id
),
),
)
if params.date_from: if params.date_from:
date_filter = (EventDate.start >= params.date_from) date_filter = EventDate.start >= params.date_from
if params.date_to: if params.date_to:
date_filter = and_(date_filter, EventDate.start < params.date_to) date_filter = and_(date_filter, EventDate.start < params.date_to)
@ -54,13 +89,21 @@ def get_event_dates_query(params):
weekdays = params.weekday weekdays = params.weekday
else: else:
weekdays = [params.weekday] weekdays = [params.weekday]
date_filter = and_(date_filter, extract('dow', EventDate.start).in_(weekdays)) date_filter = and_(date_filter, extract("dow", EventDate.start).in_(weekdays))
return (
EventDate.query.join(Event)
.join(EventPlace, isouter=True)
.join(Location, isouter=True)
.filter(date_filter)
.filter(event_filter)
.order_by(EventDate.start)
)
return EventDate.query.join(Event).join(EventPlace, isouter=True).join(Location, isouter=True).filter(date_filter).filter(event_filter).order_by(EventDate.start)
def get_events_query(params): def get_events_query(params):
event_filter = (1 == 1) event_filter = 1 == 1
date_filter = (EventDate.start >= today) date_filter = EventDate.start >= today
event_filter = fill_event_filter(event_filter, params) event_filter = fill_event_filter(event_filter, params)
@ -68,13 +111,19 @@ def get_events_query(params):
event_filter = and_(event_filter, Event.admin_unit_id == params.admin_unit_id) event_filter = and_(event_filter, Event.admin_unit_id == params.admin_unit_id)
if params.date_from: if params.date_from:
date_filter = (EventDate.start >= params.date_from) date_filter = EventDate.start >= params.date_from
if params.date_to: if params.date_to:
date_filter = and_(date_filter, EventDate.start < params.date_to) date_filter = and_(date_filter, EventDate.start < params.date_to)
event_filter = and_(event_filter, Event.dates.any(date_filter)) event_filter = and_(event_filter, Event.dates.any(date_filter))
return Event.query.join(EventPlace, isouter=True).join(Location, isouter=True).filter(event_filter).order_by(Event.start) return (
Event.query.join(EventPlace, isouter=True)
.join(Location, isouter=True)
.filter(event_filter)
.order_by(Event.start)
)
def update_event_dates_with_recurrence_rule(event, start, end): def update_event_dates_with_recurrence_rule(event, start, end):
event.start = start event.start = start
@ -92,19 +141,30 @@ def update_event_dates_with_recurrence_rule(event, start, end):
rr_dates = [start] rr_dates = [start]
for rr_date in rr_dates: for rr_date in rr_dates:
rr_date_start = date_add_time(rr_date, start.hour, start.minute, start.second, rr_date.tzinfo) rr_date_start = date_add_time(
rr_date, start.hour, start.minute, start.second, rr_date.tzinfo
)
if end: if end:
rr_date_end = rr_date_start + time_difference rr_date_end = rr_date_start + time_difference
else: else:
rr_date_end = None rr_date_end = None
existing_date = next((date for date in event.dates if date.start == rr_date_start and date.end == rr_date_end), None) existing_date = next(
(
date
for date in event.dates
if date.start == rr_date_start and date.end == rr_date_end
),
None,
)
if existing_date: if existing_date:
dates_to_remove.remove(existing_date) dates_to_remove.remove(existing_date)
else: else:
new_date = EventDate(event_id = event.id, start=rr_date_start, end=rr_date_end) new_date = EventDate(
event_id=event.id, start=rr_date_start, end=rr_date_end
)
dates_to_add.append(new_date) dates_to_add.append(new_date)
event.dates = [date for date in event.dates if date not in dates_to_remove] event.dates = [date for date in event.dates if date not in dates_to_remove]
event.dates.extend(dates_to_add) event.dates.extend(dates_to_add)

View File

@ -1,9 +1,14 @@
from project.dateutils import today, date_add_time, date_set_end_of_day, form_input_from_date, form_input_to_date from project.dateutils import (
today,
date_set_end_of_day,
form_input_from_date,
form_input_to_date,
)
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from flask import request from flask import request
class EventSearchParams(object):
class EventSearchParams(object):
def __init__(self): def __init__(self):
self._date_from = None self._date_from = None
self._date_to = None self._date_to = None
@ -77,30 +82,30 @@ class EventSearchParams(object):
self.date_to = date_set_end_of_day(today + relativedelta(months=3)) self.date_to = date_set_end_of_day(today + relativedelta(months=3))
def load_from_request(self): def load_from_request(self):
if 'date_from' in request.args: if "date_from" in request.args:
self.date_from_str = request.args['date_from'] self.date_from_str = request.args["date_from"]
if 'date_to' in request.args: if "date_to" in request.args:
self.date_to_str = request.args['date_to'] self.date_to_str = request.args["date_to"]
if 'keyword' in request.args: if "keyword" in request.args:
self.keyword = request.args['keyword'] self.keyword = request.args["keyword"]
if "coordinate" in request.args: if "coordinate" in request.args:
self.coordinate = request.args['coordinate'] self.coordinate = request.args["coordinate"]
if "distance" in request.args: if "distance" in request.args:
self.distance = request.args['distance'] self.distance = request.args["distance"]
if "category_id" in request.args: if "category_id" in request.args:
category_ids = request.args.getlist('category_id') category_ids = request.args.getlist("category_id")
if '0' in category_ids: if "0" in category_ids:
category_ids.remove('0') category_ids.remove("0")
if len(category_ids) > 0: if len(category_ids) > 0:
self.category_id = category_ids self.category_id = category_ids
if "weekday" in request.args: if "weekday" in request.args:
self.weekday = request.args.getlist('weekday') self.weekday = request.args.getlist("weekday")
if "organizer_id" in request.args: if "organizer_id" in request.args:
self.organizer_id = request.args['organizer_id'] self.organizer_id = request.args["organizer_id"]

View File

@ -1,9 +1,15 @@
from project.models import EventReviewStatus, EventSuggestion from project.models import EventReviewStatus, EventSuggestion
from sqlalchemy import and_ from sqlalchemy import and_
def get_event_reviews_badge_query(admin_unit): def get_event_reviews_badge_query(admin_unit):
return EventSuggestion.query.filter(and_(EventSuggestion.admin_unit_id == admin_unit.id, EventSuggestion.review_status == EventReviewStatus.inbox)) return EventSuggestion.query.filter(
and_(
EventSuggestion.admin_unit_id == admin_unit.id,
EventSuggestion.review_status == EventReviewStatus.inbox,
)
)
def get_event_reviews_query(admin_unit): def get_event_reviews_query(admin_unit):
return EventSuggestion.query.filter(EventSuggestion.admin_unit_id == admin_unit.id) return EventSuggestion.query.filter(EventSuggestion.admin_unit_id == admin_unit.id)

View File

@ -1,9 +1,13 @@
from project import db
from project.models import Location from project.models import Location
def upsert_location(street, postalCode, city, latitude = 0, longitude = 0, state = None):
result = Location.query.filter_by(street = street, postalCode=postalCode, city=city, state=state).first() def upsert_location(street, postalCode, city, latitude=0, longitude=0, state=None):
result = Location.query.filter_by(
street=street, postalCode=postalCode, city=city, state=state
).first()
if result is None: if result is None:
result = Location(street = street, postalCode=postalCode, city=city, state=state) result = Location(street=street, postalCode=postalCode, city=city, state=state)
db.session.add(result) db.session.add(result)
result.latitude = latitude result.latitude = latitude
@ -20,4 +24,4 @@ def assign_location_values(target, origin):
target.state = origin.state target.state = origin.state
target.country = origin.country target.country = origin.country
target.latitude = origin.latitude target.latitude = origin.latitude
target.longitude = origin.longitude target.longitude = origin.longitude

View File

@ -1,16 +1,25 @@
from project.models import EventOrganizer, EventPlace from project import db
from sqlalchemy import and_, or_, not_ from project.models import EventOrganizer, EventPlace, Location
from sqlalchemy.sql import asc, func from sqlalchemy import and_
from sqlalchemy.sql import func
def upsert_event_organizer(admin_unit_id, name): def upsert_event_organizer(admin_unit_id, name):
result = EventOrganizer.query.filter(and_(EventOrganizer.name == name, EventOrganizer.admin_unit_id == admin_unit_id)).first() result = EventOrganizer.query.filter(
and_(EventOrganizer.name == name, EventOrganizer.admin_unit_id == admin_unit_id)
).first()
if result is None: if result is None:
result = EventOrganizer(name = name, admin_unit_id=admin_unit_id) result = EventOrganizer(name=name, admin_unit_id=admin_unit_id)
result.location = Location() result.location = Location()
db.session.add(result) db.session.add(result)
return result return result
def get_event_places(organizer_id): def get_event_places(organizer_id):
organizer = EventOrganizer.query.get(organizer_id) organizer = EventOrganizer.query.get(organizer_id)
return EventPlace.query.filter(EventPlace.admin_unit_id==organizer.admin_unit_id).order_by(func.lower(EventPlace.name)).all() return (
EventPlace.query.filter(EventPlace.admin_unit_id == organizer.admin_unit_id)
.order_by(func.lower(EventPlace.name))
.all()
)

View File

@ -1,14 +1,29 @@
from project.models import EventPlace from project import db
from sqlalchemy.sql import asc, func from project.models import EventPlace, Location
from sqlalchemy.sql import and_, func
def upsert_event_place(admin_unit_id, organizer_id, name): def upsert_event_place(admin_unit_id, organizer_id, name):
result = EventPlace.query.filter(and_(EventPlace.name == name, EventPlace.admin_unit_id == admin_unit_id, EventPlace.organizer_id == organizer_id)).first() result = EventPlace.query.filter(
and_(
EventPlace.name == name,
EventPlace.admin_unit_id == admin_unit_id,
EventPlace.organizer_id == organizer_id,
)
).first()
if result is None: if result is None:
result = EventPlace(name = name, admin_unit_id=admin_unit_id, organizer_id=organizer_id) result = EventPlace(
name=name, admin_unit_id=admin_unit_id, organizer_id=organizer_id
)
result.location = Location() result.location = Location()
db.session.add(result) db.session.add(result)
return result return result
def get_event_places(admin_unit_id): def get_event_places(admin_unit_id):
return EventPlace.query.filter(EventPlace.admin_unit_id==admin_unit_id).order_by(func.lower(EventPlace.name)).all() return (
EventPlace.query.filter(EventPlace.admin_unit_id == admin_unit_id)
.order_by(func.lower(EventPlace.name))
.all()
)

View File

@ -1,20 +1,44 @@
from project import db from project import db
from project.models import EventReference, EventReferenceRequest, EventReferenceRequestReviewStatus from project.models import (
from sqlalchemy import and_, or_, not_ EventReference,
EventReferenceRequest,
EventReferenceRequestReviewStatus,
)
from sqlalchemy import and_
def create_event_reference_for_request(request): def create_event_reference_for_request(request):
result = EventReference.query.filter(and_(EventReference.event_id == request.event_id, result = EventReference.query.filter(
EventReference.admin_unit_id == request.admin_unit_id)).first() and_(
EventReference.event_id == request.event_id,
EventReference.admin_unit_id == request.admin_unit_id,
)
).first()
if result is None: if result is None:
result = EventReference(event_id = request.event_id, result = EventReference(
admin_unit_id = request.admin_unit_id) event_id=request.event_id, admin_unit_id=request.admin_unit_id
)
db.session.add(result) db.session.add(result)
return result return result
def get_reference_requests_incoming_query(admin_unit): def get_reference_requests_incoming_query(admin_unit):
return EventReferenceRequest.query.filter(and_(EventReferenceRequest.review_status != EventReferenceRequestReviewStatus.verified, EventReferenceRequest.admin_unit_id == admin_unit.id)) return EventReferenceRequest.query.filter(
and_(
EventReferenceRequest.review_status
!= EventReferenceRequestReviewStatus.verified,
EventReferenceRequest.admin_unit_id == admin_unit.id,
)
)
def get_reference_requests_incoming_badge_query(admin_unit): def get_reference_requests_incoming_badge_query(admin_unit):
return EventReferenceRequest.query.filter(and_(EventReferenceRequest.review_status == EventReferenceRequestReviewStatus.inbox, EventReferenceRequest.admin_unit_id == admin_unit.id)) return EventReferenceRequest.query.filter(
and_(
EventReferenceRequest.review_status
== EventReferenceRequestReviewStatus.inbox,
EventReferenceRequest.admin_unit_id == admin_unit.id,
)
)

View File

@ -1,17 +1,22 @@
from project import user_datastore from project import user_datastore
from flask_security import Security, current_user, auth_required, roles_required, hash_password from flask_security import hash_password
def upsert_user(email, password="password"): def upsert_user(email, password="password"):
result = user_datastore.find_user(email=email) result = user_datastore.find_user(email=email)
if result is None: if result is None:
result = user_datastore.create_user(email=email, password=hash_password(password)) result = user_datastore.create_user(
email=email, password=hash_password(password)
)
return result return result
def add_roles_to_user(user_name, role_names): def add_roles_to_user(user_name, role_names):
user = upsert_user(user_name) user = upsert_user(user_name)
for role_name in role_names: for role_name in role_names:
user_datastore.add_role_to_user(user, role_name) user_datastore.add_role_to_user(user, role_name)
def upsert_user_role(role_name, role_title, permissions): def upsert_user_role(role_name, role_title, permissions):
role = user_datastore.find_or_create_role(role_name) role = user_datastore.find_or_create_role(role_name)
role.title = role_title role.title = role_title
@ -19,5 +24,6 @@ def upsert_user_role(role_name, role_title, permissions):
role.add_permissions(permissions) role.add_permissions(permissions)
return role return role
def find_user_by_email(email): def find_user_by_email(email):
return user_datastore.find_user(email=email) return user_datastore.find_user(email=email)

View File

@ -164,7 +164,7 @@
rangeByEndDateHuman: 'ends on', rangeByEndDateHuman: 'ends on',
including: ', and also', including: ', and also',
except: ', except for', except Exception: ', except for',
cancel: 'Cancel', cancel: 'Cancel',
save: 'Save', save: 'Save',

View File

@ -51,7 +51,7 @@ jQuery.tools.recurrenceinput.localize('de', {
rangeByEndDate: 'Bis ', rangeByEndDate: 'Bis ',
rangeByEndDateHuman: 'endet am ', rangeByEndDateHuman: 'endet am ',
including: ', und auch ', including: ', und auch ',
except: ', ausser für', except Exception: ', ausser für',
cancel: 'Abbrechen', cancel: 'Abbrechen',
save: 'Speichern', save: 'Speichern',
recurrenceStart: 'Beginn der Wiederholung', recurrenceStart: 'Beginn der Wiederholung',

View File

@ -1,7 +1,9 @@
from flask_babelex import lazy_gettext from flask_babelex import lazy_gettext
def get_event_category_name(category): def get_event_category_name(category):
return lazy_gettext('Event_' + category.name) return lazy_gettext("Event_" + category.name)
def get_localized_enum_name(enum): def get_localized_enum_name(enum):
return lazy_gettext(enum.__class__.__name__ + '.' + enum.name) return lazy_gettext(enum.__class__.__name__ + "." + enum.name)

View File

@ -1,18 +1,16 @@
from project import app, db from project import app
from project.models import AdminUnit from project.models import AdminUnit
from flask import render_template, flash, url_for, redirect, request, jsonify from flask import render_template
from flask_babelex import gettext from flask_security import roles_required
from flask_security import auth_required, roles_required
from project.access import has_access, access_or_401
from sqlalchemy.sql import asc, func
@app.route("/admin") @app.route("/admin")
@roles_required("admin") @roles_required("admin")
def admin(): def admin():
return render_template('admin/admin.html') return render_template("admin/admin.html")
@app.route("/admin/admin_units") @app.route("/admin/admin_units")
@roles_required("admin") @roles_required("admin")
def admin_admin_units(): def admin_admin_units():
return render_template('admin/admin_units.html', return render_template("admin/admin_units.html", admin_units=AdminUnit.query.all())
admin_units=AdminUnit.query.all())

View File

@ -1,20 +1,26 @@
from project import app, db from project import app, db
from flask import url_for, render_template, request, redirect, flash from flask import url_for, render_template, redirect, flash
from flask_babelex import gettext from flask_babelex import gettext
from flask_security import auth_required, current_user from flask_security import auth_required, current_user
from project.models import AdminUnitMemberInvitation
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
from project.access import get_admin_unit_for_manage_or_404, access_or_401, has_access from project.access import get_admin_unit_for_manage_or_404, has_access
from project.forms.admin_unit import CreateAdminUnitForm, UpdateAdminUnitForm from project.forms.admin_unit import CreateAdminUnitForm, UpdateAdminUnitForm
from project.views.utils import upsert_image_with_data, handleSqlError, permission_missing, flash_errors from project.views.utils import (
upsert_image_with_data,
handleSqlError,
permission_missing,
flash_errors,
)
from project.models import AdminUnit, Location, EventOrganizer from project.models import AdminUnit, Location, EventOrganizer
from project.services.admin_unit import add_user_to_admin_unit_with_roles from project.services.admin_unit import add_user_to_admin_unit_with_roles
from project.services.location import assign_location_values from project.services.location import assign_location_values
def update_admin_unit_with_form(admin_unit, form): def update_admin_unit_with_form(admin_unit, form):
form.populate_obj(admin_unit) form.populate_obj(admin_unit)
@app.route("/admin_unit/create", methods=('GET', 'POST'))
@app.route("/admin_unit/create", methods=("GET", "POST"))
@auth_required() @auth_required()
def admin_unit_create(): def admin_unit_create():
form = CreateAdminUnitForm() form = CreateAdminUnitForm()
@ -28,7 +34,9 @@ def admin_unit_create():
db.session.add(admin_unit) db.session.add(admin_unit)
# Aktuellen Nutzer als Admin hinzufügen # Aktuellen Nutzer als Admin hinzufügen
add_user_to_admin_unit_with_roles(current_user, admin_unit, ['admin', 'event_verifier']) add_user_to_admin_unit_with_roles(
current_user, admin_unit, ["admin", "event_verifier"]
)
db.session.commit() db.session.commit()
# Organizer anlegen # Organizer anlegen
@ -42,27 +50,32 @@ def admin_unit_create():
organizer.location = Location() organizer.location = Location()
assign_location_values(organizer.location, admin_unit.location) assign_location_values(organizer.location, admin_unit.location)
if admin_unit.logo: if admin_unit.logo:
organizer.logo = upsert_image_with_data(organizer.logo, admin_unit.logo.data, admin_unit.logo.encoding_format) organizer.logo = upsert_image_with_data(
organizer.logo,
admin_unit.logo.data,
admin_unit.logo.encoding_format,
)
db.session.add(organizer) db.session.add(organizer)
db.session.commit() db.session.commit()
flash(gettext('Admin unit successfully created'), 'success') flash(gettext("Admin unit successfully created"), "success")
return redirect(url_for('manage_admin_unit', id=admin_unit.id)) return redirect(url_for("manage_admin_unit", id=admin_unit.id))
except SQLAlchemyError as e: except SQLAlchemyError as e:
db.session.rollback() db.session.rollback()
flash(handleSqlError(e), 'danger') flash(handleSqlError(e), "danger")
else: else:
flash_errors(form) flash_errors(form)
return render_template('admin_unit/create.html', form=form) return render_template("admin_unit/create.html", form=form)
@app.route('/admin_unit/<int:id>/update', methods=('GET', 'POST'))
@app.route("/admin_unit/<int:id>/update", methods=("GET", "POST"))
@auth_required() @auth_required()
def admin_unit_update(id): def admin_unit_update(id):
admin_unit = get_admin_unit_for_manage_or_404(id) admin_unit = get_admin_unit_for_manage_or_404(id)
if not has_access(admin_unit, 'admin_unit:update'): if not has_access(admin_unit, "admin_unit:update"):
return permission_missing(url_for('manage_admin_unit', id=admin_unit.id)) return permission_missing(url_for("manage_admin_unit", id=admin_unit.id))
form = UpdateAdminUnitForm(obj=admin_unit) form = UpdateAdminUnitForm(obj=admin_unit)
@ -71,14 +84,12 @@ def admin_unit_update(id):
try: try:
db.session.commit() db.session.commit()
flash(gettext('AdminUnit successfully updated'), 'success') flash(gettext("AdminUnit successfully updated"), "success")
return redirect(url_for('admin_unit_update', id=admin_unit.id)) return redirect(url_for("admin_unit_update", id=admin_unit.id))
except SQLAlchemyError as e: except SQLAlchemyError as e:
db.session.rollback() db.session.rollback()
flash(handleSqlError(e), 'danger') flash(handleSqlError(e), "danger")
else: else:
flash_errors(form) flash_errors(form)
return render_template('admin_unit/update.html', return render_template("admin_unit/update.html", form=form, admin_unit=admin_unit)
form=form,
admin_unit=admin_unit)

View File

@ -1,25 +1,36 @@
from project import app, db from project import app, db
from flask import url_for, render_template, request, redirect, flash from flask import url_for, render_template, redirect, flash
from flask_babelex import gettext from flask_babelex import gettext
from flask_security import auth_required, current_user from flask_security import auth_required
from project.models import AdminUnitMember, AdminUnitMemberRole from project.models import AdminUnitMember, AdminUnitMemberRole
from project.forms.admin_unit_member import DeleteAdminUnitMemberForm, UpdateAdminUnitMemberForm from project.forms.admin_unit_member import (
from project.views.utils import permission_missing, send_mail, handleSqlError, flash_errors DeleteAdminUnitMemberForm,
from project.access import get_admin_unit_for_manage_or_404, has_access UpdateAdminUnitMemberForm,
)
from project.views.utils import (
permission_missing,
handleSqlError,
flash_errors,
)
from project.access import has_access
from project.services.admin_unit import add_roles_to_admin_unit_member from project.services.admin_unit import add_roles_to_admin_unit_member
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
@app.route('/manage/member/<int:id>/update', methods=('GET', 'POST'))
@app.route("/manage/member/<int:id>/update", methods=("GET", "POST"))
@auth_required() @auth_required()
def manage_admin_unit_member_update(id): def manage_admin_unit_member_update(id):
member = AdminUnitMember.query.get_or_404(id) member = AdminUnitMember.query.get_or_404(id)
admin_unit = member.adminunit admin_unit = member.adminunit
if not has_access(admin_unit, 'admin_unit.members:update'): if not has_access(admin_unit, "admin_unit.members:update"):
return permission_missing(url_for('manage_admin_unit', id=admin_unit.id)) return permission_missing(url_for("manage_admin_unit", id=admin_unit.id))
form = UpdateAdminUnitMemberForm() form = UpdateAdminUnitMemberForm()
form.roles.choices = [(c.name, gettext(c.title)) for c in AdminUnitMemberRole.query.order_by(AdminUnitMemberRole.id).all()] form.roles.choices = [
(c.name, gettext(c.title))
for c in AdminUnitMemberRole.query.order_by(AdminUnitMemberRole.id).all()
]
if form.validate_on_submit(): if form.validate_on_submit():
member.roles.clear() member.roles.clear()
@ -27,45 +38,43 @@ def manage_admin_unit_member_update(id):
try: try:
db.session.commit() db.session.commit()
flash(gettext('Member successfully updated'), 'success') flash(gettext("Member successfully updated"), "success")
return redirect(url_for('manage_admin_unit_members', id=admin_unit.id)) return redirect(url_for("manage_admin_unit_members", id=admin_unit.id))
except SQLAlchemyError as e: except SQLAlchemyError as e:
db.session.rollback() db.session.rollback()
flash(handleSqlError(e), 'danger') flash(handleSqlError(e), "danger")
else: else:
form.roles.data = [c.name for c in member.roles] form.roles.data = [c.name for c in member.roles]
return render_template('admin_unit/update_member.html', return render_template(
admin_unit=admin_unit, "admin_unit/update_member.html", admin_unit=admin_unit, member=member, form=form
member=member, )
form=form)
@app.route('/manage/member/<int:id>/delete', methods=('GET', 'POST'))
@app.route("/manage/member/<int:id>/delete", methods=("GET", "POST"))
@auth_required() @auth_required()
def manage_admin_unit_member_delete(id): def manage_admin_unit_member_delete(id):
member = AdminUnitMember.query.get_or_404(id) member = AdminUnitMember.query.get_or_404(id)
admin_unit = member.adminunit admin_unit = member.adminunit
if not has_access(admin_unit, 'admin_unit.members:delete'): if not has_access(admin_unit, "admin_unit.members:delete"):
return permission_missing(url_for('manage_admin_unit', id=admin_unit.id)) return permission_missing(url_for("manage_admin_unit", id=admin_unit.id))
form = DeleteAdminUnitMemberForm() form = DeleteAdminUnitMemberForm()
if form.validate_on_submit(): if form.validate_on_submit():
if form.email.data != member.user.email: if form.email.data != member.user.email:
flash(gettext('Entered email does not match member email'), 'danger') flash(gettext("Entered email does not match member email"), "danger")
else: else:
try: try:
db.session.delete(member) db.session.delete(member)
db.session.commit() db.session.commit()
flash(gettext('Member successfully deleted'), 'success') flash(gettext("Member successfully deleted"), "success")
return redirect(url_for('manage_admin_unit_members', id=admin_unit.id)) return redirect(url_for("manage_admin_unit_members", id=admin_unit.id))
except SQLAlchemyError as e: except SQLAlchemyError as e:
db.session.rollback() db.session.rollback()
flash(handleSqlError(e), 'danger') flash(handleSqlError(e), "danger")
else: else:
flash_errors(form) flash_errors(form)
return render_template('manage/delete_member.html', return render_template("manage/delete_member.html", form=form, member=member)
form=form,
member=member)

View File

@ -1,113 +1,130 @@
from project import app, db from project import app, db
from flask import url_for, render_template, request, redirect, flash from flask import url_for, render_template, redirect, flash
from flask_babelex import gettext from flask_babelex import gettext
from flask_security import auth_required, current_user from flask_security import auth_required, current_user
from project.models import AdminUnitMemberInvitation, AdminUnitMemberRole from project.models import AdminUnitMemberInvitation, AdminUnitMemberRole
from project.forms.admin_unit_member import NegotiateAdminUnitMemberInvitationForm, InviteAdminUnitMemberForm, DeleteAdminUnitInvitationForm from project.forms.admin_unit_member import (
from project.views.utils import permission_missing, send_mail, handleSqlError, flash_errors NegotiateAdminUnitMemberInvitationForm,
InviteAdminUnitMemberForm,
DeleteAdminUnitInvitationForm,
)
from project.views.utils import (
permission_missing,
send_mail,
handleSqlError,
flash_errors,
)
from project.access import get_admin_unit_for_manage_or_404, has_access from project.access import get_admin_unit_for_manage_or_404, has_access
from project.services.admin_unit import add_user_to_admin_unit_with_roles from project.services.admin_unit import add_user_to_admin_unit_with_roles
from project.services.user import find_user_by_email from project.services.user import find_user_by_email
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
@app.route('/invitations/<int:id>', methods=('GET', 'POST'))
@app.route("/invitations/<int:id>", methods=("GET", "POST"))
def admin_unit_member_invitation(id): def admin_unit_member_invitation(id):
invitation = AdminUnitMemberInvitation.query.get_or_404(id) invitation = AdminUnitMemberInvitation.query.get_or_404(id)
# Wenn Email nicht als Nutzer vorhanden, dann direkt zu Registrierung # Wenn Email nicht als Nutzer vorhanden, dann direkt zu Registrierung
if not find_user_by_email(invitation.email): if not find_user_by_email(invitation.email):
return redirect(url_for('security.register')) return redirect(url_for("security.register"))
if not current_user.is_authenticated: if not current_user.is_authenticated:
return app.login_manager.unauthorized() return app.login_manager.unauthorized()
if invitation.email != current_user.email: if invitation.email != current_user.email:
return permission_missing(url_for('profile')) return permission_missing(url_for("profile"))
form = NegotiateAdminUnitMemberInvitationForm() form = NegotiateAdminUnitMemberInvitationForm()
if form.validate_on_submit(): if form.validate_on_submit():
try: try:
if form.accept.data: if form.accept.data:
message = gettext('Invitation successfully accepted') message = gettext("Invitation successfully accepted")
roles = invitation.roles.split(',') roles = invitation.roles.split(",")
add_user_to_admin_unit_with_roles(current_user, invitation.adminunit, roles) add_user_to_admin_unit_with_roles(
current_user, invitation.adminunit, roles
)
else: else:
message = gettext('Invitation successfully declined') message = gettext("Invitation successfully declined")
db.session.delete(invitation) db.session.delete(invitation)
db.session.commit() db.session.commit()
flash(message, 'success') flash(message, "success")
return redirect(url_for('manage')) return redirect(url_for("manage"))
except SQLAlchemyError as e: except SQLAlchemyError as e:
db.session.rollback() db.session.rollback()
flash(handleSqlError(e), 'danger') flash(handleSqlError(e), "danger")
return render_template('invitation/read.html', return render_template("invitation/read.html", form=form, invitation=invitation)
form=form,
invitation=invitation)
@app.route('/manage/admin_unit/<int:id>/members/invite', methods=('GET', 'POST'))
@app.route("/manage/admin_unit/<int:id>/members/invite", methods=("GET", "POST"))
@auth_required() @auth_required()
def manage_admin_unit_member_invite(id): def manage_admin_unit_member_invite(id):
admin_unit = get_admin_unit_for_manage_or_404(id) admin_unit = get_admin_unit_for_manage_or_404(id)
if not has_access(admin_unit, 'admin_unit.members:invite'): if not has_access(admin_unit, "admin_unit.members:invite"):
return permission_missing(url_for('manage_admin_unit', id=admin_unit.id)) return permission_missing(url_for("manage_admin_unit", id=admin_unit.id))
form = InviteAdminUnitMemberForm() form = InviteAdminUnitMemberForm()
form.roles.choices = [(c.name, gettext(c.title)) for c in AdminUnitMemberRole.query.order_by(AdminUnitMemberRole.id).all()] form.roles.choices = [
(c.name, gettext(c.title))
for c in AdminUnitMemberRole.query.order_by(AdminUnitMemberRole.id).all()
]
if form.validate_on_submit(): if form.validate_on_submit():
invitation = AdminUnitMemberInvitation() invitation = AdminUnitMemberInvitation()
invitation.admin_unit_id = admin_unit.id invitation.admin_unit_id = admin_unit.id
form.populate_obj(invitation) form.populate_obj(invitation)
invitation.roles = ','.join(form.roles.data) invitation.roles = ",".join(form.roles.data)
try: try:
db.session.add(invitation) db.session.add(invitation)
db.session.commit() db.session.commit()
send_mail(invitation.email, send_mail(
gettext('You have received an invitation'), invitation.email,
'invitation_notice', gettext("You have received an invitation"),
invitation=invitation) "invitation_notice",
invitation=invitation,
)
flash(gettext('Invitation successfully sent'), 'success') flash(gettext("Invitation successfully sent"), "success")
return redirect(url_for('manage_admin_unit_members', id=admin_unit.id)) return redirect(url_for("manage_admin_unit_members", id=admin_unit.id))
except SQLAlchemyError as e: except SQLAlchemyError as e:
db.session.rollback() db.session.rollback()
flash(handleSqlError(e), 'danger') flash(handleSqlError(e), "danger")
return render_template('admin_unit/invite_member.html', return render_template(
admin_unit=admin_unit, "admin_unit/invite_member.html", admin_unit=admin_unit, form=form
form=form) )
@app.route('/manage/invitation/<int:id>/delete', methods=('GET', 'POST'))
@app.route("/manage/invitation/<int:id>/delete", methods=("GET", "POST"))
@auth_required() @auth_required()
def manage_admin_unit_invitation_delete(id): def manage_admin_unit_invitation_delete(id):
invitation = AdminUnitMemberInvitation.query.get_or_404(id) invitation = AdminUnitMemberInvitation.query.get_or_404(id)
admin_unit = invitation.adminunit admin_unit = invitation.adminunit
if not has_access(admin_unit, 'admin_unit.members:invite'): if not has_access(admin_unit, "admin_unit.members:invite"):
return permission_missing(url_for('manage_admin_unit', id=id)) return permission_missing(url_for("manage_admin_unit", id=id))
form = DeleteAdminUnitInvitationForm() form = DeleteAdminUnitInvitationForm()
if form.validate_on_submit(): if form.validate_on_submit():
if form.email.data != invitation.email: if form.email.data != invitation.email:
flash(gettext('Entered email does not match invitation email'), 'danger') flash(gettext("Entered email does not match invitation email"), "danger")
else: else:
try: try:
db.session.delete(invitation) db.session.delete(invitation)
db.session.commit() db.session.commit()
flash(gettext('Invitation successfully deleted'), 'success') flash(gettext("Invitation successfully deleted"), "success")
return redirect(url_for('manage_admin_unit_members', id=admin_unit.id)) return redirect(url_for("manage_admin_unit_members", id=admin_unit.id))
except SQLAlchemyError as e: except SQLAlchemyError as e:
db.session.rollback() db.session.rollback()
flash(handleSqlError(e), 'danger') flash(handleSqlError(e), "danger")
else: else:
flash_errors(form) flash_errors(form)
return render_template('manage/delete_invitation.html', return render_template(
form=form, "manage/delete_invitation.html", form=form, invitation=invitation
invitation=invitation) )

View File

@ -7,11 +7,18 @@ from project.services.event import get_event_dates_query
from project.services.event_search import EventSearchParams from project.services.event_search import EventSearchParams
from project.services.organizer import get_event_places from project.services.organizer import get_event_places
@app.route("/api/events") @app.route("/api/events")
def api_events(): def api_events():
dates = EventDate.query.join(Event).filter(EventDate.start >= today).order_by(EventDate.start).all() dates = (
EventDate.query.join(Event)
.filter(EventDate.start >= today)
.order_by(EventDate.start)
.all()
)
return json_from_event_dates(dates) return json_from_event_dates(dates)
@app.route("/api/event_dates") @app.route("/api/event_dates")
def api_event_dates(): def api_event_dates():
params = EventSearchParams() params = EventSearchParams()
@ -20,9 +27,12 @@ def api_event_dates():
dates = get_event_dates_query(params).paginate() dates = get_event_dates_query(params).paginate()
return json_from_event_dates(dates.items) return json_from_event_dates(dates.items)
@app.route("/api/<string:au_short_name>/event_dates") @app.route("/api/<string:au_short_name>/event_dates")
def api_infoscreen(au_short_name): def api_infoscreen(au_short_name):
admin_unit = AdminUnit.query.filter(AdminUnit.short_name == au_short_name).first_or_404() admin_unit = AdminUnit.query.filter(
AdminUnit.short_name == au_short_name
).first_or_404()
params = EventSearchParams() params = EventSearchParams()
params.load_from_request() params.load_from_request()
@ -31,6 +41,7 @@ def api_infoscreen(au_short_name):
dates = get_event_dates_query(params).paginate() dates = get_event_dates_query(params).paginate()
return json_from_event_dates(dates.items) return json_from_event_dates(dates.items)
@app.route("/api/organizer/<int:id>/event_places") @app.route("/api/organizer/<int:id>/event_places")
def api_event_places(id): def api_event_places(id):
places = get_event_places(id) places = get_event_places(id)
@ -44,16 +55,17 @@ def api_event_places(id):
return jsonify(result) return jsonify(result)
def json_from_event_dates(dates): def json_from_event_dates(dates):
structured_events = list() structured_events = list()
for event_date in dates: for event_date in dates:
structured_event = get_sd_for_event_date(event_date) structured_event = get_sd_for_event_date(event_date)
structured_event.pop('@context', None) structured_event.pop("@context", None)
structured_events.append(structured_event) structured_events.append(structured_event)
result = {} result = {}
result["@context"] = "https://schema.org" result["@context"] = "https://schema.org"
result["@type"] = "Project" result["@type"] = "Project"
result["name"] = "Prototyp" result["name"] = "Prototyp"
result['event'] = structured_events result["event"] = structured_events
return jsonify(result) return jsonify(result)

View File

@ -1,58 +1,95 @@
from project import app, db from project import app, db
from project.models import User, Event, EventDate, EventReviewStatus, AdminUnit, AdminUnitMember, EventOrganizer, EventCategory, EventSuggestion from project.models import (
from flask import render_template, flash, url_for, redirect, request, jsonify, abort Event,
EventDate,
EventReviewStatus,
AdminUnit,
EventOrganizer,
EventCategory,
EventSuggestion,
)
from flask import render_template, flash, url_for, redirect, request, jsonify
from flask_babelex import gettext from flask_babelex import gettext
from flask_security import auth_required from project.access import (
from project.access import has_access, access_or_401, can_reference_event, has_admin_unit_member_permission has_access,
access_or_401,
can_reference_event,
)
from project.dateutils import today from project.dateutils import today
from datetime import datetime from datetime import datetime
from project.forms.event import CreateEventForm, UpdateEventForm, DeleteEventForm from project.forms.event import CreateEventForm, UpdateEventForm, DeleteEventForm
from project.views.utils import flash_errors, upsert_image_with_data, send_mail, handleSqlError, flash_message from project.views.utils import (
flash_errors,
handleSqlError,
flash_message,
)
from project.utils import get_event_category_name from project.utils import get_event_category_name
from project.services.event import upsert_event_category, update_event_dates_with_recurrence_rule from project.services.event import (
upsert_event_category,
update_event_dates_with_recurrence_rule,
)
from project.services.place import get_event_places from project.services.place import get_event_places
from sqlalchemy.sql import asc, func from sqlalchemy.sql import func
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
from project.views.event_suggestion import send_event_suggestion_review_status_mail from project.views.event_suggestion import send_event_suggestion_review_status_mail
@app.route('/event/<int:event_id>')
@app.route("/event/<int:event_id>")
def event(event_id): def event(event_id):
event = Event.query.get_or_404(event_id) event = Event.query.get_or_404(event_id)
user_rights = get_user_rights(event) user_rights = get_user_rights(event)
dates = EventDate.query.with_parent(event).filter(EventDate.start >= today).order_by(EventDate.start).all() dates = (
EventDate.query.with_parent(event)
.filter(EventDate.start >= today)
.order_by(EventDate.start)
.all()
)
return render_template('event/read.html', return render_template(
event=event, "event/read.html", event=event, dates=dates, user_rights=user_rights
dates=dates, )
user_rights=user_rights)
@app.route("/admin_unit/<int:id>/events/create", methods=('GET', 'POST'))
@app.route("/admin_unit/<int:id>/events/create", methods=("GET", "POST"))
def event_create_for_admin_unit_id(id): def event_create_for_admin_unit_id(id):
admin_unit = AdminUnit.query.get_or_404(id) admin_unit = AdminUnit.query.get_or_404(id)
access_or_401(admin_unit, 'event:create') access_or_401(admin_unit, "event:create")
form = CreateEventForm(admin_unit_id=admin_unit.id, category_ids=[upsert_event_category('Other').id]) form = CreateEventForm(
admin_unit_id=admin_unit.id, category_ids=[upsert_event_category("Other").id]
)
prepare_event_form(form, admin_unit) prepare_event_form(form, admin_unit)
# Vorlagen # Vorlagen
event_suggestion = None event_suggestion = None
event_template = None event_template = None
event_template_id = int(request.args.get('template_id')) if 'template_id' in request.args else 0 event_template_id = (
int(request.args.get("template_id")) if "template_id" in request.args else 0
)
if event_template_id > 0: if event_template_id > 0:
event_template = Event.query.get_or_404(event_template_id) event_template = Event.query.get_or_404(event_template_id)
if not form.is_submitted(): if not form.is_submitted():
form.process(obj=event_template) form.process(obj=event_template)
if not event_template: if not event_template:
event_suggestion_id = int(request.args.get('event_suggestion_id')) if 'event_suggestion_id' in request.args else 0 event_suggestion_id = (
int(request.args.get("event_suggestion_id"))
if "event_suggestion_id" in request.args
else 0
)
if event_suggestion_id > 0: if event_suggestion_id > 0:
event_suggestion = EventSuggestion.query.get_or_404(event_suggestion_id) event_suggestion = EventSuggestion.query.get_or_404(event_suggestion_id)
access_or_401(event_suggestion.admin_unit, 'event:verify') access_or_401(event_suggestion.admin_unit, "event:verify")
if event_suggestion.verified and event_suggestion.event_id: if event_suggestion.verified and event_suggestion.event_id:
return redirect(url_for('event_suggestion_review_status', event_suggestion_id=event_suggestion.id)) return redirect(
url_for(
"event_suggestion_review_status",
event_suggestion_id=event_suggestion.id,
)
)
prepare_event_form_for_suggestion(form, event_suggestion) prepare_event_form_for_suggestion(form, event_suggestion)
if form.is_submitted(): if form.is_submitted():
@ -81,21 +118,27 @@ def event_create_for_admin_unit_id(id):
if event_suggestion: if event_suggestion:
send_event_suggestion_review_status_mail(event_suggestion) send_event_suggestion_review_status_mail(event_suggestion)
flash_message(gettext('Event successfully created'), url_for('event', event_id=event.id)) flash_message(
return redirect(url_for('manage_admin_unit_events', id=event.admin_unit_id)) gettext("Event successfully created"),
url_for("event", event_id=event.id),
)
return redirect(url_for("manage_admin_unit_events", id=event.admin_unit_id))
except SQLAlchemyError as e: except SQLAlchemyError as e:
db.session.rollback() db.session.rollback()
flash(handleSqlError(e), 'danger') flash(handleSqlError(e), "danger")
else: else:
flash_errors(form) flash_errors(form)
return render_template('event/create.html', form=form, event_suggestion=event_suggestion) return render_template(
"event/create.html", form=form, event_suggestion=event_suggestion
)
@app.route('/event/<int:event_id>/update', methods=('GET', 'POST'))
@app.route("/event/<int:event_id>/update", methods=("GET", "POST"))
def event_update(event_id): def event_update(event_id):
event = Event.query.get_or_404(event_id) event = Event.query.get_or_404(event_id)
access_or_401(event.admin_unit, 'event:update') access_or_401(event.admin_unit, "event:update")
form = UpdateEventForm(obj=event,start=event.start,end=event.end) form = UpdateEventForm(obj=event, start=event.start, end=event.end)
prepare_event_form(form, event.admin_unit) prepare_event_form(form, event.admin_unit)
if not form.is_submitted(): if not form.is_submitted():
@ -106,72 +149,86 @@ def event_update(event_id):
try: try:
db.session.commit() db.session.commit()
flash_message(gettext('Event successfully updated'), url_for('event', event_id=event.id)) flash_message(
return redirect(url_for('manage_admin_unit_events', id=event.admin_unit_id)) gettext("Event successfully updated"),
url_for("event", event_id=event.id),
)
return redirect(url_for("manage_admin_unit_events", id=event.admin_unit_id))
except SQLAlchemyError as e: except SQLAlchemyError as e:
db.session.rollback() db.session.rollback()
flash(handleSqlError(e), 'danger') flash(handleSqlError(e), "danger")
else: else:
flash_errors(form) flash_errors(form)
return render_template('event/update.html', return render_template("event/update.html", form=form, event=event)
form=form,
event=event)
@app.route('/event/<int:event_id>/delete', methods=('GET', 'POST'))
@app.route("/event/<int:event_id>/delete", methods=("GET", "POST"))
def event_delete(event_id): def event_delete(event_id):
event = Event.query.get_or_404(event_id) event = Event.query.get_or_404(event_id)
access_or_401(event.admin_unit, 'event:delete') access_or_401(event.admin_unit, "event:delete")
form = DeleteEventForm() form = DeleteEventForm()
if form.validate_on_submit(): if form.validate_on_submit():
if form.name.data != event.name: if form.name.data != event.name:
flash(gettext('Entered name does not match event name'), 'danger') flash(gettext("Entered name does not match event name"), "danger")
else: else:
try: try:
admin_unit_id = event.admin_unit.id admin_unit_id = event.admin_unit.id
db.session.delete(event) db.session.delete(event)
db.session.commit() db.session.commit()
flash(gettext('Event successfully deleted'), 'success') flash(gettext("Event successfully deleted"), "success")
return redirect(url_for('manage_admin_unit_events', id=admin_unit_id)) return redirect(url_for("manage_admin_unit_events", id=admin_unit_id))
except SQLAlchemyError as e: except SQLAlchemyError as e:
db.session.rollback() db.session.rollback()
flash(handleSqlError(e), 'danger') flash(handleSqlError(e), "danger")
else: else:
flash_errors(form) flash_errors(form)
return render_template('event/delete.html', return render_template("event/delete.html", form=form, event=event)
form=form,
event=event)
@app.route("/events/rrule", methods=['POST'])
@app.route("/events/rrule", methods=["POST"])
def event_rrule(): def event_rrule():
year = request.json['year'] year = request.json["year"]
month = request.json['month'] month = request.json["month"]
day = request.json['day'] day = request.json["day"]
rrule_str = request.json['rrule'] rrule_str = request.json["rrule"]
output_format = request.json['format'] start = int(request.json["start"])
start = int(request.json['start'])
batch_size = 10 batch_size = 10
start_date = datetime(year, month, day) start_date = datetime(year, month, day)
from project.dateutils import calculate_occurrences from project.dateutils import calculate_occurrences
result = calculate_occurrences(start_date, '"%d.%m.%Y"', rrule_str, start, batch_size)
result = calculate_occurrences(
start_date, '"%d.%m.%Y"', rrule_str, start, batch_size
)
return jsonify(result) return jsonify(result)
def get_event_category_choices(): def get_event_category_choices():
return sorted([(c.id, get_event_category_name(c)) for c in EventCategory.query.all()], key=lambda category: category[1]) return sorted(
[(c.id, get_event_category_name(c)) for c in EventCategory.query.all()],
key=lambda category: category[1],
)
def prepare_event_form(form, admin_unit): def prepare_event_form(form, admin_unit):
form.organizer_id.choices = [(o.id, o.name) for o in EventOrganizer.query.filter(EventOrganizer.admin_unit_id == admin_unit.id).order_by(func.lower(EventOrganizer.name))] form.organizer_id.choices = [
(o.id, o.name)
for o in EventOrganizer.query.filter(
EventOrganizer.admin_unit_id == admin_unit.id
).order_by(func.lower(EventOrganizer.name))
]
form.category_ids.choices = get_event_category_choices() form.category_ids.choices = get_event_category_choices()
places = get_event_places(admin_unit.id) places = get_event_places(admin_unit.id)
form.event_place_id.choices = [(p.id, p.name) for p in places] form.event_place_id.choices = [(p.id, p.name) for p in places]
form.organizer_id.choices.insert(0, (0, '')) form.organizer_id.choices.insert(0, (0, ""))
form.event_place_id.choices.insert(0, (0, '')) form.event_place_id.choices.insert(0, (0, ""))
def prepare_event_form_for_suggestion(form, event_suggestion): def prepare_event_form_for_suggestion(form, event_suggestion):
form.name.data = event_suggestion.name form.name.data = event_suggestion.name
@ -194,16 +251,22 @@ def prepare_event_form_for_suggestion(form, event_suggestion):
form.organizer_choice.data = 2 form.organizer_choice.data = 2
form.new_organizer.form.name.data = event_suggestion.organizer_text form.new_organizer.form.name.data = event_suggestion.organizer_text
def update_event_with_form(event, form, event_suggestion = None):
def update_event_with_form(event, form, event_suggestion=None):
form.populate_obj(event) form.populate_obj(event)
event.categories = EventCategory.query.filter(EventCategory.id.in_(form.category_ids.data)).all() event.categories = EventCategory.query.filter(
EventCategory.id.in_(form.category_ids.data)
).all()
update_event_dates_with_recurrence_rule(event, form.start.data, form.end.data) update_event_dates_with_recurrence_rule(event, form.start.data, form.end.data)
def get_user_rights(event): def get_user_rights(event):
return { return {
"can_duplicate_event": has_access(event.admin_unit, 'event:create'), "can_duplicate_event": has_access(event.admin_unit, "event:create"),
"can_verify_event": has_access(event.admin_unit, 'event:verify'), "can_verify_event": has_access(event.admin_unit, "event:verify"),
"can_update_event": has_access(event.admin_unit, 'event:update'), "can_update_event": has_access(event.admin_unit, "event:update"),
"can_reference_event": can_reference_event(event), "can_reference_event": can_reference_event(event),
"can_create_reference_request": has_access(event.admin_unit, 'reference_request:create') "can_create_reference_request": has_access(
} event.admin_unit, "reference_request:create"
),
}

View File

@ -1,21 +1,18 @@
from project import app, db from project import app
from project.models import Event, EventDate, EventReviewStatus from project.models import EventDate
from flask import render_template, flash, url_for, redirect, request from flask import render_template, url_for, redirect, request
from flask_babelex import gettext from project.views.utils import flash_errors, track_analytics
from project.dateutils import today, date_set_end_of_day, form_input_from_date, form_input_to_date
from dateutil.relativedelta import relativedelta
from project.views.utils import flash_errors, track_analytics, get_pagination_urls
from sqlalchemy import and_, or_, not_
import json import json
from project.jsonld import get_sd_for_event_date, DateTimeEncoder from project.jsonld import get_sd_for_event_date, DateTimeEncoder
from project.services.event_search import EventSearchParams from project.services.event_search import EventSearchParams
from project.services.event import get_event_dates_query
from project.forms.event_date import FindEventDateForm from project.forms.event_date import FindEventDateForm
from project.views.event import get_event_category_choices, get_user_rights from project.views.event import get_event_category_choices, get_user_rights
def prepare_event_date_form(form): def prepare_event_date_form(form):
form.category_id.choices = get_event_category_choices() form.category_id.choices = get_event_category_choices()
form.category_id.choices.insert(0, (0, '')) form.category_id.choices.insert(0, (0, ""))
@app.route("/eventdates") @app.route("/eventdates")
def event_dates(): def event_dates():
@ -30,20 +27,23 @@ def event_dates():
else: else:
flash_errors(form) flash_errors(form)
return render_template('event_date/list.html', return render_template("event_date/list.html", form=form, params=params)
form=form,
params=params)
@app.route('/eventdate/<int:id>')
@app.route("/eventdate/<int:id>")
def event_date(id): def event_date(id):
event_date = EventDate.query.get_or_404(id) event_date = EventDate.query.get_or_404(id)
if 'src' in request.args: if "src" in request.args:
track_analytics("event_date", str(id), request.args['src']) track_analytics("event_date", str(id), request.args["src"])
return redirect(url_for('event_date', id=id)) return redirect(url_for("event_date", id=id))
structured_data = json.dumps(get_sd_for_event_date(event_date), indent=2, cls=DateTimeEncoder) structured_data = json.dumps(
return render_template('event_date/read.html', get_sd_for_event_date(event_date), indent=2, cls=DateTimeEncoder
)
return render_template(
"event_date/read.html",
event_date=event_date, event_date=event_date,
structured_data=structured_data, structured_data=structured_data,
user_rights = get_user_rights(event_date.event)) user_rights=get_user_rights(event_date.event),
)

View File

@ -1,19 +1,26 @@
from project import app, db from project import app, db
from project.models import EventOrganizer, EventPlace, Location from project.models import EventPlace, Location
from flask import render_template, flash, url_for, redirect, request, jsonify from flask import render_template, flash, url_for, redirect
from flask_babelex import gettext from flask_babelex import gettext
from flask_security import auth_required from flask_security import auth_required
from project.access import has_access, access_or_401, get_admin_unit_for_manage_or_404 from project.access import access_or_401, get_admin_unit_for_manage_or_404
from project.forms.event_place import UpdateEventPlaceForm, CreateEventPlaceForm, DeleteEventPlaceForm from project.forms.event_place import (
from project.views.utils import flash_errors, upsert_image_with_data, send_mail, handleSqlError UpdateEventPlaceForm,
from sqlalchemy.sql import asc, func CreateEventPlaceForm,
DeleteEventPlaceForm,
)
from project.views.utils import (
flash_errors,
handleSqlError,
)
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
@app.route('/manage/admin_unit/<int:id>/places/create', methods=('GET', 'POST'))
@app.route("/manage/admin_unit/<int:id>/places/create", methods=("GET", "POST"))
@auth_required() @auth_required()
def manage_admin_unit_places_create(id): def manage_admin_unit_places_create(id):
admin_unit = get_admin_unit_for_manage_or_404(id) admin_unit = get_admin_unit_for_manage_or_404(id)
access_or_401(admin_unit, 'place:create') access_or_401(admin_unit, "place:create")
form = CreateEventPlaceForm() form = CreateEventPlaceForm()
@ -26,18 +33,19 @@ def manage_admin_unit_places_create(id):
try: try:
db.session.add(place) db.session.add(place)
db.session.commit() db.session.commit()
flash(gettext('Place successfully created'), 'success') flash(gettext("Place successfully created"), "success")
return redirect(url_for('manage_admin_unit_event_places', id=admin_unit.id)) return redirect(url_for("manage_admin_unit_event_places", id=admin_unit.id))
except SQLAlchemyError as e: except SQLAlchemyError as e:
db.session.rollback() db.session.rollback()
flash(handleSqlError(e), 'danger') flash(handleSqlError(e), "danger")
return render_template('event_place/create.html', form=form) return render_template("event_place/create.html", form=form)
@app.route('/event_place/<int:id>/update', methods=('GET', 'POST'))
@app.route("/event_place/<int:id>/update", methods=("GET", "POST"))
@auth_required() @auth_required()
def event_place_update(id): def event_place_update(id):
place = EventPlace.query.get_or_404(id) place = EventPlace.query.get_or_404(id)
access_or_401(place.adminunit, 'place:update') access_or_401(place.adminunit, "place:update")
form = UpdateEventPlaceForm(obj=place) form = UpdateEventPlaceForm(obj=place)
@ -46,44 +54,45 @@ def event_place_update(id):
try: try:
db.session.commit() db.session.commit()
flash(gettext('Place successfully updated'), 'success') flash(gettext("Place successfully updated"), "success")
return redirect(url_for('manage_admin_unit_event_places', id=place.admin_unit_id)) return redirect(
url_for("manage_admin_unit_event_places", id=place.admin_unit_id)
)
except SQLAlchemyError as e: except SQLAlchemyError as e:
db.session.rollback() db.session.rollback()
flash(handleSqlError(e), 'danger') flash(handleSqlError(e), "danger")
return render_template('event_place/update.html', return render_template("event_place/update.html", form=form, place=place)
form=form,
place=place)
@app.route('/event_place/<int:id>/delete', methods=('GET', 'POST'))
@app.route("/event_place/<int:id>/delete", methods=("GET", "POST"))
@auth_required() @auth_required()
def event_place_delete(id): def event_place_delete(id):
place = EventPlace.query.get_or_404(id) place = EventPlace.query.get_or_404(id)
access_or_401(place.adminunit, 'place:delete') access_or_401(place.adminunit, "place:delete")
form = DeleteEventPlaceForm() form = DeleteEventPlaceForm()
if form.validate_on_submit(): if form.validate_on_submit():
if form.name.data != place.name: if form.name.data != place.name:
flash(gettext('Entered name does not match place name'), 'danger') flash(gettext("Entered name does not match place name"), "danger")
else: else:
try: try:
admin_unit_id=place.admin_unit_id admin_unit_id = place.admin_unit_id
db.session.delete(place) db.session.delete(place)
db.session.commit() db.session.commit()
flash(gettext('Place successfully deleted'), 'success') flash(gettext("Place successfully deleted"), "success")
return redirect(url_for('manage_admin_unit_event_places', id=admin_unit_id)) return redirect(
url_for("manage_admin_unit_event_places", id=admin_unit_id)
)
except SQLAlchemyError as e: except SQLAlchemyError as e:
db.session.rollback() db.session.rollback()
flash(handleSqlError(e), 'danger') flash(handleSqlError(e), "danger")
else: else:
flash_errors(form) flash_errors(form)
return render_template('event_place/delete.html', return render_template("event_place/delete.html", form=form, place=place)
form=form,
place=place)
def update_event_place_with_form(place, form): def update_event_place_with_form(place, form):
form.populate_obj(place) form.populate_obj(place)

View File

@ -1,34 +1,39 @@
from project import app, db from project import app, db
from project.models import EventSuggestion, User, Event, EventDate, EventReviewStatus, AdminUnit, AdminUnitMember, EventOrganizer, EventCategory from project.models import (
from flask import render_template, flash, url_for, redirect, request, jsonify, abort EventSuggestion,
EventReviewStatus,
)
from flask import render_template, flash, url_for, redirect
from flask_babelex import gettext from flask_babelex import gettext
from flask_security import current_user from project.access import access_or_401
from project.access import has_access, access_or_401, can_reference_event, has_admin_unit_member_permission
from project.dateutils import today
from datetime import datetime
from project.forms.event_suggestion import RejectEventSuggestionForm from project.forms.event_suggestion import RejectEventSuggestionForm
from project.views.utils import flash_errors, send_mail, handleSqlError, flash_message from project.views.utils import flash_errors, send_mail, handleSqlError
from project.utils import get_event_category_name
from project.services.event import upsert_event_category, update_event_dates_with_recurrence_rule
from sqlalchemy.sql import asc, func
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
@app.route('/event_suggestion/<int:event_suggestion_id>/review')
@app.route("/event_suggestion/<int:event_suggestion_id>/review")
def event_suggestion_review(event_suggestion_id): def event_suggestion_review(event_suggestion_id):
event_suggestion = EventSuggestion.query.get_or_404(event_suggestion_id) event_suggestion = EventSuggestion.query.get_or_404(event_suggestion_id)
access_or_401(event_suggestion.admin_unit, 'event:verify') access_or_401(event_suggestion.admin_unit, "event:verify")
return render_template('event_suggestion/review.html', return render_template(
"event_suggestion/review.html",
admin_unit=event_suggestion.admin_unit, admin_unit=event_suggestion.admin_unit,
event_suggestion=event_suggestion) event_suggestion=event_suggestion,
)
@app.route('/event_suggestion/<int:event_suggestion_id>/reject', methods=('GET', 'POST'))
@app.route(
"/event_suggestion/<int:event_suggestion_id>/reject", methods=("GET", "POST")
)
def event_suggestion_reject(event_suggestion_id): def event_suggestion_reject(event_suggestion_id):
event_suggestion = EventSuggestion.query.get_or_404(event_suggestion_id) event_suggestion = EventSuggestion.query.get_or_404(event_suggestion_id)
access_or_401(event_suggestion.admin_unit, 'event:verify') access_or_401(event_suggestion.admin_unit, "event:verify")
if event_suggestion.verified: if event_suggestion.verified:
return redirect(url_for('event_suggestion_review', event_suggestion_id=event_suggestion.id)) return redirect(
url_for("event_suggestion_review", event_suggestion_id=event_suggestion.id)
)
form = RejectEventSuggestionForm(obj=event_suggestion) form = RejectEventSuggestionForm(obj=event_suggestion)
@ -42,29 +47,40 @@ def event_suggestion_reject(event_suggestion_id):
try: try:
db.session.commit() db.session.commit()
send_event_suggestion_review_status_mail(event_suggestion) send_event_suggestion_review_status_mail(event_suggestion)
flash(gettext('Event suggestion successfully rejected'), 'success') flash(gettext("Event suggestion successfully rejected"), "success")
return redirect(url_for('manage_admin_unit_event_reviews', id=event_suggestion.admin_unit_id)) return redirect(
url_for(
"manage_admin_unit_event_reviews", id=event_suggestion.admin_unit_id
)
)
except SQLAlchemyError as e: except SQLAlchemyError as e:
db.session.rollback() db.session.rollback()
flash(handleSqlError(e), 'danger') flash(handleSqlError(e), "danger")
else: else:
flash_errors(form) flash_errors(form)
return render_template('event_suggestion/reject.html', return render_template(
"event_suggestion/reject.html",
form=form, form=form,
admin_unit=event_suggestion.admin_unit, admin_unit=event_suggestion.admin_unit,
event_suggestion=event_suggestion) event_suggestion=event_suggestion,
)
@app.route('/event_suggestion/<int:event_suggestion_id>/review_status')
@app.route("/event_suggestion/<int:event_suggestion_id>/review_status")
def event_suggestion_review_status(event_suggestion_id): def event_suggestion_review_status(event_suggestion_id):
event_suggestion = EventSuggestion.query.get_or_404(event_suggestion_id) event_suggestion = EventSuggestion.query.get_or_404(event_suggestion_id)
return render_template('event_suggestion/review_status.html', return render_template(
event_suggestion=event_suggestion) "event_suggestion/review_status.html", event_suggestion=event_suggestion
)
def send_event_suggestion_review_status_mail(event_suggestion): def send_event_suggestion_review_status_mail(event_suggestion):
if event_suggestion.contact_email and event_suggestion.contact_email_notice: if event_suggestion.contact_email and event_suggestion.contact_email_notice:
send_mail(event_suggestion.contact_email, send_mail(
gettext('Event review status updated'), event_suggestion.contact_email,
'review_status_notice', gettext("Event review status updated"),
event_suggestion=event_suggestion) "review_status_notice",
event_suggestion=event_suggestion,
)

View File

@ -1,7 +1,8 @@
from project import app from project import app
from project.models import Image from project.models import Image
@app.route('/image/<int:id>')
@app.route("/image/<int:id>")
def image(id): def image(id):
image = Image.query.get_or_404(id) image = Image.query.get_or_404(id)
return app.response_class(image.data, mimetype=image.encoding_format) return app.response_class(image.data, mimetype=image.encoding_format)

View File

@ -1,12 +1,36 @@
from project import app, db from project import app, db
from project.models import AdminUnit, AdminUnitMember, AdminUnitMemberInvitation, Event, EventPlace, EventReviewStatus, EventOrganizer, User, EventSuggestion from project.models import (
from flask import render_template, flash, url_for, redirect, request, jsonify, make_response AdminUnitMember,
AdminUnitMemberInvitation,
EventPlace,
EventOrganizer,
User,
EventSuggestion,
)
from flask import (
render_template,
flash,
url_for,
redirect,
request,
make_response,
)
from flask_babelex import gettext from flask_babelex import gettext
from flask_security import auth_required, roles_required, current_user from flask_security import auth_required, current_user
from project.access import has_access, access_or_401, get_admin_unit_for_manage, get_admin_units_for_manage, get_admin_unit_for_manage_or_404 from project.access import (
from sqlalchemy.sql import asc, desc, func has_access,
from sqlalchemy import and_, or_, not_ get_admin_unit_for_manage,
from project.views.utils import get_pagination_urls, permission_missing, handleSqlError, flash_errors get_admin_units_for_manage,
get_admin_unit_for_manage_or_404,
)
from sqlalchemy.sql import desc, func
from sqlalchemy.exc import SQLAlchemyError
from project.views.utils import (
get_pagination_urls,
permission_missing,
handleSqlError,
flash_errors,
)
from project.forms.event_place import FindEventPlaceForm from project.forms.event_place import FindEventPlaceForm
from project.forms.event import FindEventForm from project.forms.event import FindEventForm
from project.forms.admin_unit import UpdateAdminUnitWidgetForm from project.forms.admin_unit import UpdateAdminUnitWidgetForm
@ -15,57 +39,72 @@ from project.services.event import get_events_query
from project.services.event_suggestion import get_event_reviews_query from project.services.event_suggestion import get_event_reviews_query
from project.views.event import get_event_category_choices from project.views.event import get_event_category_choices
@app.route("/manage") @app.route("/manage")
@auth_required() @auth_required()
def manage(): def manage():
try: try:
if 'manage_admin_unit_id' in request.cookies: if "manage_admin_unit_id" in request.cookies:
manage_admin_unit_id = int(request.cookies.get('manage_admin_unit_id')) manage_admin_unit_id = int(request.cookies.get("manage_admin_unit_id"))
admin_unit = get_admin_unit_for_manage(manage_admin_unit_id) admin_unit = get_admin_unit_for_manage(manage_admin_unit_id)
if admin_unit: if admin_unit:
return redirect(url_for('manage_admin_unit', id=admin_unit.id)) return redirect(url_for("manage_admin_unit", id=admin_unit.id))
except: except Exception:
pass pass
return redirect(url_for('manage_admin_units')) return redirect(url_for("manage_admin_units"))
@app.route("/manage/admin_units") @app.route("/manage/admin_units")
@auth_required() @auth_required()
def manage_admin_units(): def manage_admin_units():
admin_units = get_admin_units_for_manage() admin_units = get_admin_units_for_manage()
invitations = AdminUnitMemberInvitation.query.filter(AdminUnitMemberInvitation.email == current_user.email).all() invitations = AdminUnitMemberInvitation.query.filter(
AdminUnitMemberInvitation.email == current_user.email
).all()
admin_units.sort(key=lambda x: x.name) admin_units.sort(key=lambda x: x.name)
invitations.sort(key=lambda x: x.adminunit.name) invitations.sort(key=lambda x: x.adminunit.name)
return render_template('manage/admin_units.html', return render_template(
invitations=invitations, "manage/admin_units.html", invitations=invitations, admin_units=admin_units
admin_units=admin_units) )
@app.route('/manage/admin_unit/<int:id>')
@app.route("/manage/admin_unit/<int:id>")
@auth_required() @auth_required()
def manage_admin_unit(id): def manage_admin_unit(id):
admin_unit = get_admin_unit_for_manage_or_404(id) admin_unit = get_admin_unit_for_manage_or_404(id)
response = make_response(redirect(url_for('manage_admin_unit_events', id=admin_unit.id))) response = make_response(
response.set_cookie('manage_admin_unit_id', str(admin_unit.id)) redirect(url_for("manage_admin_unit_events", id=admin_unit.id))
)
response.set_cookie("manage_admin_unit_id", str(admin_unit.id))
return response return response
@app.route('/manage/admin_unit/<int:id>/reviews')
@app.route("/manage/admin_unit/<int:id>/reviews")
@auth_required() @auth_required()
def manage_admin_unit_event_reviews(id): def manage_admin_unit_event_reviews(id):
admin_unit = get_admin_unit_for_manage_or_404(id) admin_unit = get_admin_unit_for_manage_or_404(id)
event_suggestions_paginate = get_event_reviews_query(admin_unit).order_by(desc(EventSuggestion.created_at)).paginate() event_suggestions_paginate = (
get_event_reviews_query(admin_unit)
.order_by(desc(EventSuggestion.created_at))
.paginate()
)
event_suggestions = event_suggestions_paginate.items event_suggestions = event_suggestions_paginate.items
return render_template('manage/reviews.html', return render_template(
"manage/reviews.html",
admin_unit=admin_unit, admin_unit=admin_unit,
event_suggestions=event_suggestions, event_suggestions=event_suggestions,
pagination = get_pagination_urls(event_suggestions_paginate, id=id)) pagination=get_pagination_urls(event_suggestions_paginate, id=id),
)
@app.route('/manage/admin_unit/<int:id>/events')
@app.route("/manage/admin_unit/<int:id>/events")
@auth_required() @auth_required()
def manage_admin_unit_events(id): def manage_admin_unit_events(id):
admin_unit = get_admin_unit_for_manage_or_404(id) admin_unit = get_admin_unit_for_manage_or_404(id)
@ -75,72 +114,107 @@ def manage_admin_unit_events(id):
form = FindEventForm(formdata=request.args, obj=params) form = FindEventForm(formdata=request.args, obj=params)
form.category_id.choices = get_event_category_choices() form.category_id.choices = get_event_category_choices()
form.category_id.choices.insert(0, (0, '')) form.category_id.choices.insert(0, (0, ""))
organizers = EventOrganizer.query.filter(EventOrganizer.admin_unit_id == admin_unit.id).order_by(func.lower(EventOrganizer.name)).all() organizers = (
EventOrganizer.query.filter(EventOrganizer.admin_unit_id == admin_unit.id)
.order_by(func.lower(EventOrganizer.name))
.all()
)
form.organizer_id.choices = [(o.id, o.name) for o in organizers] form.organizer_id.choices = [(o.id, o.name) for o in organizers]
form.organizer_id.choices.insert(0, (0, '')) form.organizer_id.choices.insert(0, (0, ""))
if form.validate(): if form.validate():
form.populate_obj(params) form.populate_obj(params)
params.admin_unit_id = admin_unit.id params.admin_unit_id = admin_unit.id
events = get_events_query(params).paginate() events = get_events_query(params).paginate()
return render_template('manage/events.html', return render_template(
"manage/events.html",
admin_unit=admin_unit, admin_unit=admin_unit,
form=form, form=form,
events=events.items, events=events.items,
pagination=get_pagination_urls(events, id=id)) pagination=get_pagination_urls(events, id=id),
)
@app.route('/manage/admin_unit/<int:id>/organizers')
@app.route("/manage/admin_unit/<int:id>/organizers")
@auth_required() @auth_required()
def manage_admin_unit_organizers(id): def manage_admin_unit_organizers(id):
admin_unit = get_admin_unit_for_manage_or_404(id) admin_unit = get_admin_unit_for_manage_or_404(id)
organizers = EventOrganizer.query.filter(EventOrganizer.admin_unit_id == admin_unit.id).order_by(func.lower(EventOrganizer.name)).paginate() organizers = (
EventOrganizer.query.filter(EventOrganizer.admin_unit_id == admin_unit.id)
.order_by(func.lower(EventOrganizer.name))
.paginate()
)
return render_template('manage/organizers.html', return render_template(
"manage/organizers.html",
admin_unit=admin_unit, admin_unit=admin_unit,
organizers=organizers.items, organizers=organizers.items,
pagination=get_pagination_urls(organizers, id=id)) pagination=get_pagination_urls(organizers, id=id),
)
@app.route('/manage/admin_unit/<int:id>/event_places')
@app.route("/manage/admin_unit/<int:id>/event_places")
@auth_required() @auth_required()
def manage_admin_unit_event_places(id): def manage_admin_unit_event_places(id):
admin_unit = get_admin_unit_for_manage_or_404(id) admin_unit = get_admin_unit_for_manage_or_404(id)
form = FindEventPlaceForm(**request.args) form = FindEventPlaceForm(**request.args)
places = EventPlace.query.filter(EventPlace.admin_unit_id == admin_unit.id).order_by(func.lower(EventPlace.name)).paginate() places = (
return render_template('manage/places.html', EventPlace.query.filter(EventPlace.admin_unit_id == admin_unit.id)
.order_by(func.lower(EventPlace.name))
.paginate()
)
return render_template(
"manage/places.html",
admin_unit=admin_unit, admin_unit=admin_unit,
form=form, form=form,
places=places.items, places=places.items,
pagination=get_pagination_urls(places, id=id)) pagination=get_pagination_urls(places, id=id),
)
@app.route('/manage/admin_unit/<int:id>/members')
@app.route("/manage/admin_unit/<int:id>/members")
@auth_required() @auth_required()
def manage_admin_unit_members(id): def manage_admin_unit_members(id):
admin_unit = get_admin_unit_for_manage_or_404(id) admin_unit = get_admin_unit_for_manage_or_404(id)
if not has_access(admin_unit, 'admin_unit.members:read'): if not has_access(admin_unit, "admin_unit.members:read"):
return permission_missing(url_for('manage_admin_unit', id=id)) return permission_missing(url_for("manage_admin_unit", id=id))
members = AdminUnitMember.query.join(User).filter(AdminUnitMember.admin_unit_id == admin_unit.id).order_by(func.lower(User.email)).paginate() members = (
invitations = AdminUnitMemberInvitation.query.filter(AdminUnitMemberInvitation.admin_unit_id == admin_unit.id).order_by(func.lower(AdminUnitMemberInvitation.email)).all() AdminUnitMember.query.join(User)
.filter(AdminUnitMember.admin_unit_id == admin_unit.id)
.order_by(func.lower(User.email))
.paginate()
)
invitations = (
AdminUnitMemberInvitation.query.filter(
AdminUnitMemberInvitation.admin_unit_id == admin_unit.id
)
.order_by(func.lower(AdminUnitMemberInvitation.email))
.all()
)
return render_template('manage/members.html', return render_template(
"manage/members.html",
admin_unit=admin_unit, admin_unit=admin_unit,
can_invite_users=has_access(admin_unit, 'admin_unit.members:invite'), can_invite_users=has_access(admin_unit, "admin_unit.members:invite"),
members=members.items, members=members.items,
invitations=invitations, invitations=invitations,
pagination=get_pagination_urls(members, id=id)) pagination=get_pagination_urls(members, id=id),
)
@app.route('/manage/admin_unit/<int:id>/widgets', methods=('GET', 'POST'))
@app.route("/manage/admin_unit/<int:id>/widgets", methods=("GET", "POST"))
@auth_required() @auth_required()
def manage_admin_unit_widgets(id): def manage_admin_unit_widgets(id):
admin_unit = get_admin_unit_for_manage_or_404(id) admin_unit = get_admin_unit_for_manage_or_404(id)
default_background_color = '#ffffff' default_background_color = "#ffffff"
default_primary_color = '#007bff' default_primary_color = "#007bff"
form = UpdateAdminUnitWidgetForm(obj=admin_unit) form = UpdateAdminUnitWidgetForm(obj=admin_unit)
@ -154,8 +228,8 @@ def manage_admin_unit_widgets(id):
form.widget_link_color.data = default_primary_color form.widget_link_color.data = default_primary_color
if form.validate_on_submit(): if form.validate_on_submit():
if not has_access(admin_unit, 'admin_unit:update'): if not has_access(admin_unit, "admin_unit:update"):
return permission_missing(url_for('manage_admin_unit', id=admin_unit.id)) return permission_missing(url_for("manage_admin_unit", id=admin_unit.id))
form.populate_obj(admin_unit) form.populate_obj(admin_unit)
@ -170,14 +244,12 @@ def manage_admin_unit_widgets(id):
try: try:
db.session.commit() db.session.commit()
flash(gettext('Settings successfully updated'), 'success') flash(gettext("Settings successfully updated"), "success")
return redirect(url_for('manage_admin_unit_widgets', id=admin_unit.id)) return redirect(url_for("manage_admin_unit_widgets", id=admin_unit.id))
except SQLAlchemyError as e: except SQLAlchemyError as e:
db.session.rollback() db.session.rollback()
flash(handleSqlError(e), 'danger') flash(handleSqlError(e), "danger")
else: else:
flash_errors(form) flash_errors(form)
return render_template('manage/widgets.html', return render_template("manage/widgets.html", form=form, admin_unit=admin_unit)
form=form,
admin_unit=admin_unit)

View File

@ -1,19 +1,26 @@
from project import app, db from project import app, db
from project.models import EventOrganizer, Location from project.models import EventOrganizer, Location
from flask import render_template, flash, url_for, redirect, request, jsonify from flask import render_template, flash, url_for, redirect
from flask_babelex import gettext from flask_babelex import gettext
from flask_security import auth_required from flask_security import auth_required
from project.access import has_access, access_or_401, get_admin_unit_for_manage_or_404 from project.access import access_or_401, get_admin_unit_for_manage_or_404
from project.forms.organizer import CreateOrganizerForm, UpdateOrganizerForm, DeleteOrganizerForm from project.forms.organizer import (
from project.views.utils import flash_errors, upsert_image_with_data, send_mail, handleSqlError CreateOrganizerForm,
from sqlalchemy.sql import asc, func UpdateOrganizerForm,
DeleteOrganizerForm,
)
from project.views.utils import (
flash_errors,
handleSqlError,
)
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
@app.route('/manage/admin_unit/<int:id>/organizers/create', methods=('GET', 'POST'))
@app.route("/manage/admin_unit/<int:id>/organizers/create", methods=("GET", "POST"))
@auth_required() @auth_required()
def manage_admin_unit_organizer_create(id): def manage_admin_unit_organizer_create(id):
admin_unit = get_admin_unit_for_manage_or_404(id) admin_unit = get_admin_unit_for_manage_or_404(id)
access_or_401(admin_unit, 'organizer:create') access_or_401(admin_unit, "organizer:create")
form = CreateOrganizerForm() form = CreateOrganizerForm()
@ -26,18 +33,21 @@ def manage_admin_unit_organizer_create(id):
try: try:
db.session.add(organizer) db.session.add(organizer)
db.session.commit() db.session.commit()
flash(gettext('Organizer successfully created'), 'success') flash(gettext("Organizer successfully created"), "success")
return redirect(url_for('manage_admin_unit_organizers', id=organizer.admin_unit_id)) return redirect(
url_for("manage_admin_unit_organizers", id=organizer.admin_unit_id)
)
except SQLAlchemyError as e: except SQLAlchemyError as e:
db.session.rollback() db.session.rollback()
flash(handleSqlError(e), 'danger') flash(handleSqlError(e), "danger")
return render_template('organizer/create.html', form=form) return render_template("organizer/create.html", form=form)
@app.route('/organizer/<int:id>/update', methods=('GET', 'POST'))
@app.route("/organizer/<int:id>/update", methods=("GET", "POST"))
@auth_required() @auth_required()
def organizer_update(id): def organizer_update(id):
organizer = EventOrganizer.query.get_or_404(id) organizer = EventOrganizer.query.get_or_404(id)
access_or_401(organizer.adminunit, 'organizer:update') access_or_401(organizer.adminunit, "organizer:update")
form = UpdateOrganizerForm(obj=organizer) form = UpdateOrganizerForm(obj=organizer)
@ -46,42 +56,44 @@ def organizer_update(id):
try: try:
db.session.commit() db.session.commit()
flash(gettext('Organizer successfully updated'), 'success') flash(gettext("Organizer successfully updated"), "success")
return redirect(url_for('manage_admin_unit_organizers', id=organizer.admin_unit_id)) return redirect(
url_for("manage_admin_unit_organizers", id=organizer.admin_unit_id)
)
except SQLAlchemyError as e: except SQLAlchemyError as e:
db.session.rollback() db.session.rollback()
flash(handleSqlError(e), 'danger') flash(handleSqlError(e), "danger")
return render_template('organizer/update.html', return render_template("organizer/update.html", form=form, organizer=organizer)
form=form,
organizer=organizer)
@app.route('/organizer/<int:id>/delete', methods=('GET', 'POST'))
@app.route("/organizer/<int:id>/delete", methods=("GET", "POST"))
@auth_required() @auth_required()
def organizer_delete(id): def organizer_delete(id):
organizer = EventOrganizer.query.get_or_404(id) organizer = EventOrganizer.query.get_or_404(id)
access_or_401(organizer.adminunit, 'organizer:delete') access_or_401(organizer.adminunit, "organizer:delete")
form = DeleteOrganizerForm() form = DeleteOrganizerForm()
if form.validate_on_submit(): if form.validate_on_submit():
if form.name.data != organizer.name: if form.name.data != organizer.name:
flash(gettext('Entered name does not match organizer name'), 'danger') flash(gettext("Entered name does not match organizer name"), "danger")
else: else:
try: try:
db.session.delete(organizer) db.session.delete(organizer)
db.session.commit() db.session.commit()
flash(gettext('Organizer successfully deleted'), 'success') flash(gettext("Organizer successfully deleted"), "success")
return redirect(url_for('manage_admin_unit_organizers', id=organizer.admin_unit_id)) return redirect(
url_for("manage_admin_unit_organizers", id=organizer.admin_unit_id)
)
except SQLAlchemyError as e: except SQLAlchemyError as e:
db.session.rollback() db.session.rollback()
flash(handleSqlError(e), 'danger') flash(handleSqlError(e), "danger")
else: else:
flash_errors(form) flash_errors(form)
return render_template('organizer/delete.html', return render_template("organizer/delete.html", form=form, organizer=organizer)
form=form,
organizer=organizer)
def update_organizer_with_form(organizer, form): def update_organizer_with_form(organizer, form):
form.populate_obj(organizer) form.populate_obj(organizer)

View File

@ -1,21 +1,14 @@
from project import app, db from project import app
from project.models import Event, EventDate, EventReviewStatus from flask import render_template, request
from flask import render_template, flash, url_for, redirect, request
from flask_babelex import gettext
from project.dateutils import today, date_set_end_of_day, form_input_from_date, form_input_to_date
from dateutil.relativedelta import relativedelta
from project.views.utils import flash_errors, track_analytics, get_pagination_urls
from sqlalchemy import and_, or_, not_
import json
from project.jsonld import get_sd_for_event_date, DateTimeEncoder
from project.services.event_search import EventSearchParams from project.services.event_search import EventSearchParams
from project.services.event import get_event_dates_query
from project.forms.planing import PlaningForm from project.forms.planing import PlaningForm
from project.views.event import get_event_category_choices from project.views.event import get_event_category_choices
def prepare_event_date_form(form): def prepare_event_date_form(form):
form.category_id.choices = get_event_category_choices() form.category_id.choices = get_event_category_choices()
form.category_id.choices.insert(0, (0, '')) form.category_id.choices.insert(0, (0, ""))
@app.route("/planing") @app.route("/planing")
def planing(): def planing():
@ -25,6 +18,4 @@ def planing():
form = PlaningForm(formdata=request.args, obj=params) form = PlaningForm(formdata=request.args, obj=params)
prepare_event_date_form(form) prepare_event_date_form(form)
return render_template('planing/list.html', return render_template("planing/list.html", form=form, params=params)
form=form,
params=params)

View File

@ -1,7 +1,14 @@
from project import app, db from project import app, db
from project.views.utils import get_pagination_urls, flash_errors, handleSqlError from project.views.utils import get_pagination_urls, flash_errors, handleSqlError
from project.access import get_admin_unit_for_manage_or_404, get_admin_units_for_event_reference from project.access import (
from project.forms.reference import CreateEventReferenceForm, UpdateEventReferenceForm, DeleteReferenceForm get_admin_unit_for_manage_or_404,
get_admin_units_for_event_reference,
)
from project.forms.reference import (
CreateEventReferenceForm,
UpdateEventReferenceForm,
DeleteReferenceForm,
)
from flask import render_template, flash, redirect, url_for, abort from flask import render_template, flash, redirect, url_for, abort
from flask_babelex import gettext from flask_babelex import gettext
from flask_security import auth_required from flask_security import auth_required
@ -10,7 +17,8 @@ from project.access import access_or_401, can_reference_event
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.sql import desc from sqlalchemy.sql import desc
@app.route('/event/<int:event_id>/reference', methods=('GET', 'POST'))
@app.route("/event/<int:event_id>/reference", methods=("GET", "POST"))
def event_reference(event_id): def event_reference(event_id):
event = Event.query.get_or_404(event_id) event = Event.query.get_or_404(event_id)
user_can_reference_event = can_reference_event(event) user_can_reference_event = can_reference_event(event)
@ -19,7 +27,13 @@ def event_reference(event_id):
abort(401) abort(401)
form = CreateEventReferenceForm() form = CreateEventReferenceForm()
form.admin_unit_id.choices = sorted([(admin_unit.id, admin_unit.name) for admin_unit in get_admin_units_for_event_reference(event)], key=lambda admin_unit: admin_unit[1]) form.admin_unit_id.choices = sorted(
[
(admin_unit.id, admin_unit.name)
for admin_unit in get_admin_units_for_event_reference(event)
],
key=lambda admin_unit: admin_unit[1],
)
if form.validate_on_submit(): if form.validate_on_submit():
reference = EventReference() reference = EventReference()
@ -29,22 +43,21 @@ def event_reference(event_id):
try: try:
db.session.add(reference) db.session.add(reference)
db.session.commit() db.session.commit()
flash(gettext('Event successfully referenced'), 'success') flash(gettext("Event successfully referenced"), "success")
return redirect(url_for('event', event_id=event.id)) return redirect(url_for("event", event_id=event.id))
except SQLAlchemyError as e: except SQLAlchemyError as e:
db.session.rollback() db.session.rollback()
flash(handleSqlError(e), 'danger') flash(handleSqlError(e), "danger")
else: else:
flash_errors(form) flash_errors(form)
return render_template('event/reference.html', return render_template("event/reference.html", form=form, event=event)
form=form,
event=event)
@app.route('/reference/<int:id>/update', methods=('GET', 'POST'))
@app.route("/reference/<int:id>/update", methods=("GET", "POST"))
def event_reference_update(id): def event_reference_update(id):
reference = EventReference.query.get_or_404(id) reference = EventReference.query.get_or_404(id)
access_or_401(reference.admin_unit, 'reference:update') access_or_401(reference.admin_unit, "reference:update")
form = UpdateEventReferenceForm(obj=reference) form = UpdateEventReferenceForm(obj=reference)
@ -53,62 +66,83 @@ def event_reference_update(id):
try: try:
db.session.commit() db.session.commit()
flash(gettext('Reference successfully updated'), 'success') flash(gettext("Reference successfully updated"), "success")
return redirect(url_for('manage_admin_unit_references_incoming', id=reference.admin_unit_id)) return redirect(
url_for(
"manage_admin_unit_references_incoming", id=reference.admin_unit_id
)
)
except SQLAlchemyError as e: except SQLAlchemyError as e:
db.session.rollback() db.session.rollback()
flash(handleSqlError(e), 'danger') flash(handleSqlError(e), "danger")
else: else:
flash_errors(form) flash_errors(form)
return render_template('reference/update.html', return render_template("reference/update.html", form=form, reference=reference)
form=form,
reference=reference)
@app.route('/manage/admin_unit/<int:id>/references/incoming')
@app.route("/manage/admin_unit/<int:id>/references/incoming")
@auth_required() @auth_required()
def manage_admin_unit_references_incoming(id): def manage_admin_unit_references_incoming(id):
admin_unit = get_admin_unit_for_manage_or_404(id) admin_unit = get_admin_unit_for_manage_or_404(id)
references = EventReference.query.filter(EventReference.admin_unit_id == admin_unit.id).order_by(desc(EventReference.created_at)).paginate() references = (
EventReference.query.filter(EventReference.admin_unit_id == admin_unit.id)
.order_by(desc(EventReference.created_at))
.paginate()
)
return render_template('manage/references_incoming.html', return render_template(
"manage/references_incoming.html",
admin_unit=admin_unit, admin_unit=admin_unit,
references=references.items, references=references.items,
pagination=get_pagination_urls(references, id=id)) pagination=get_pagination_urls(references, id=id),
)
@app.route('/manage/admin_unit/<int:id>/references/outgoing')
@app.route("/manage/admin_unit/<int:id>/references/outgoing")
@auth_required() @auth_required()
def manage_admin_unit_references_outgoing(id): def manage_admin_unit_references_outgoing(id):
admin_unit = get_admin_unit_for_manage_or_404(id) admin_unit = get_admin_unit_for_manage_or_404(id)
references = EventReference.query.join(Event).filter(Event.admin_unit_id == admin_unit.id).order_by(desc(EventReference.created_at)).paginate() references = (
EventReference.query.join(Event)
.filter(Event.admin_unit_id == admin_unit.id)
.order_by(desc(EventReference.created_at))
.paginate()
)
return render_template('manage/references_outgoing.html', return render_template(
"manage/references_outgoing.html",
admin_unit=admin_unit, admin_unit=admin_unit,
references=references.items, references=references.items,
pagination=get_pagination_urls(references, id=id)) pagination=get_pagination_urls(references, id=id),
)
@app.route('/reference/<int:id>/delete', methods=('GET', 'POST'))
@app.route("/reference/<int:id>/delete", methods=("GET", "POST"))
def reference_delete(id): def reference_delete(id):
reference = EventReference.query.get_or_404(id) reference = EventReference.query.get_or_404(id)
access_or_401(reference.admin_unit, 'reference:delete') access_or_401(reference.admin_unit, "reference:delete")
form = DeleteReferenceForm() form = DeleteReferenceForm()
if form.validate_on_submit(): if form.validate_on_submit():
if form.name.data != reference.event.name: if form.name.data != reference.event.name:
flash(gettext('Entered name does not match event name'), 'danger') flash(gettext("Entered name does not match event name"), "danger")
else: else:
try: try:
db.session.delete(reference) db.session.delete(reference)
db.session.commit() db.session.commit()
flash(gettext('Reference successfully deleted'), 'success') flash(gettext("Reference successfully deleted"), "success")
return redirect(url_for('manage_admin_unit_references_incoming', id=reference.admin_unit_id)) return redirect(
url_for(
"manage_admin_unit_references_incoming",
id=reference.admin_unit_id,
)
)
except SQLAlchemyError as e: except SQLAlchemyError as e:
db.session.rollback() db.session.rollback()
flash(handleSqlError(e), 'danger') flash(handleSqlError(e), "danger")
else: else:
flash_errors(form) flash_errors(form)
return render_template('reference/delete.html', return render_template("reference/delete.html", form=form, reference=reference)
form=form,
reference=reference)

View File

@ -1,45 +1,79 @@
from project import app, db from project import app, db
from project.views.utils import get_pagination_urls, flash_errors, handleSqlError, send_mail from project.views.utils import (
from project.forms.reference_request import CreateEventReferenceRequestForm, DeleteReferenceRequestForm get_pagination_urls,
flash_errors,
handleSqlError,
send_mail,
)
from project.forms.reference_request import CreateEventReferenceRequestForm
from flask import render_template, flash, redirect, url_for from flask import render_template, flash, redirect, url_for
from flask_babelex import gettext from flask_babelex import gettext
from flask_security import auth_required from flask_security import auth_required
from project.models import EventReferenceRequest, Event, AdminUnit, AdminUnitMember, User, EventReferenceRequestReviewStatus from project.models import (
from project.access import access_or_401, get_admin_unit_for_manage_or_404, has_admin_unit_member_permission EventReferenceRequest,
Event,
AdminUnit,
AdminUnitMember,
User,
EventReferenceRequestReviewStatus,
)
from project.access import (
access_or_401,
get_admin_unit_for_manage_or_404,
has_admin_unit_member_permission,
)
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy import and_, or_, not_
from sqlalchemy.sql import desc from sqlalchemy.sql import desc
from project.services.reference import get_reference_requests_incoming_query from project.services.reference import get_reference_requests_incoming_query
@app.route('/manage/admin_unit/<int:id>/reference_requests/incoming')
@app.route("/manage/admin_unit/<int:id>/reference_requests/incoming")
@auth_required() @auth_required()
def manage_admin_unit_reference_requests_incoming(id): def manage_admin_unit_reference_requests_incoming(id):
admin_unit = get_admin_unit_for_manage_or_404(id) admin_unit = get_admin_unit_for_manage_or_404(id)
requests = get_reference_requests_incoming_query(admin_unit).order_by(desc(EventReferenceRequest.created_at)).paginate() requests = (
get_reference_requests_incoming_query(admin_unit)
.order_by(desc(EventReferenceRequest.created_at))
.paginate()
)
return render_template('manage/reference_requests_incoming.html', return render_template(
"manage/reference_requests_incoming.html",
admin_unit=admin_unit, admin_unit=admin_unit,
requests=requests.items, requests=requests.items,
pagination=get_pagination_urls(requests, id=id)) pagination=get_pagination_urls(requests, id=id),
)
@app.route('/manage/admin_unit/<int:id>/reference_requests/outgoing')
@app.route("/manage/admin_unit/<int:id>/reference_requests/outgoing")
@auth_required() @auth_required()
def manage_admin_unit_reference_requests_outgoing(id): def manage_admin_unit_reference_requests_outgoing(id):
admin_unit = get_admin_unit_for_manage_or_404(id) admin_unit = get_admin_unit_for_manage_or_404(id)
requests = EventReferenceRequest.query.join(Event).filter(Event.admin_unit_id == admin_unit.id).order_by(desc(EventReferenceRequest.created_at)).paginate() requests = (
EventReferenceRequest.query.join(Event)
.filter(Event.admin_unit_id == admin_unit.id)
.order_by(desc(EventReferenceRequest.created_at))
.paginate()
)
return render_template('manage/reference_requests_outgoing.html', return render_template(
"manage/reference_requests_outgoing.html",
admin_unit=admin_unit, admin_unit=admin_unit,
requests=requests.items, requests=requests.items,
pagination=get_pagination_urls(requests, id=id)) pagination=get_pagination_urls(requests, id=id),
)
@app.route('/event/<int:event_id>/reference_request/create', methods=('GET', 'POST'))
@app.route("/event/<int:event_id>/reference_request/create", methods=("GET", "POST"))
def event_reference_request_create(event_id): def event_reference_request_create(event_id):
event = Event.query.get_or_404(event_id) event = Event.query.get_or_404(event_id)
access_or_401(event.admin_unit, 'reference_request:create') access_or_401(event.admin_unit, "reference_request:create")
form = CreateEventReferenceRequestForm() form = CreateEventReferenceRequestForm()
form.admin_unit_id.choices = sorted([(admin_unit.id, admin_unit.name) for admin_unit in AdminUnit.query.all()], key=lambda admin_unit: admin_unit[1]) form.admin_unit_id.choices = sorted(
[(admin_unit.id, admin_unit.name) for admin_unit in AdminUnit.query.all()],
key=lambda admin_unit: admin_unit[1],
)
if form.validate_on_submit(): if form.validate_on_submit():
request = EventReferenceRequest() request = EventReferenceRequest()
@ -51,25 +85,30 @@ def event_reference_request_create(event_id):
db.session.add(request) db.session.add(request)
db.session.commit() db.session.commit()
send_reference_request_inbox_mails(request) send_reference_request_inbox_mails(request)
flash(gettext('Request successfully created'), 'success') flash(gettext("Request successfully created"), "success")
return redirect(url_for('event', event_id=event.id)) return redirect(url_for("event", event_id=event.id))
except SQLAlchemyError as e: except SQLAlchemyError as e:
db.session.rollback() db.session.rollback()
flash(handleSqlError(e), 'danger') flash(handleSqlError(e), "danger")
else: else:
flash_errors(form) flash_errors(form)
return render_template('event/reference_request.html', return render_template("event/reference_request.html", form=form, event=event)
form=form,
event=event)
def send_reference_request_inbox_mails(request): def send_reference_request_inbox_mails(request):
# Benachrichtige alle Mitglieder der AdminUnit, die diesen Request verifizieren können # Benachrichtige alle Mitglieder der AdminUnit, die diesen Request verifizieren können
members = AdminUnitMember.query.join(User).filter(AdminUnitMember.admin_unit_id == request.admin_unit_id).all() members = (
AdminUnitMember.query.join(User)
.filter(AdminUnitMember.admin_unit_id == request.admin_unit_id)
.all()
)
for member in members: for member in members:
if has_admin_unit_member_permission(member, 'reference_request:verify'): if has_admin_unit_member_permission(member, "reference_request:verify"):
send_mail(member.user.email, send_mail(
gettext('New reference request'), member.user.email,
'reference_request_notice', gettext("New reference request"),
request=request) "reference_request_notice",
request=request,
)

View File

@ -1,23 +1,38 @@
from project import app, db from project import app, db
from project.models import Event, EventDate, EventReferenceRequest, EventReferenceRequestReviewStatus, AdminUnitMember, User from project.models import (
EventDate,
EventReferenceRequest,
EventReferenceRequestReviewStatus,
AdminUnitMember,
User,
)
from flask import render_template, flash, url_for, redirect, abort from flask import render_template, flash, url_for, redirect, abort
from flask_babelex import gettext from flask_babelex import gettext
from flask_security import auth_required from project.access import (
from project.access import has_access, access_or_401, can_reference_event, has_admin_unit_member_permission has_access,
access_or_401,
has_admin_unit_member_permission,
)
from project.dateutils import today from project.dateutils import today
from project.forms.reference_request import ReferenceRequestReviewForm from project.forms.reference_request import ReferenceRequestReviewForm
from project.views.utils import flash_errors, send_mail, handleSqlError from project.views.utils import flash_errors, send_mail, handleSqlError
from project.services.reference import create_event_reference_for_request from project.services.reference import create_event_reference_for_request
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
@app.route('/reference_request/<int:id>/review', methods=('GET', 'POST'))
@app.route("/reference_request/<int:id>/review", methods=("GET", "POST"))
def event_reference_request_review(id): def event_reference_request_review(id):
request = EventReferenceRequest.query.get_or_404(id) request = EventReferenceRequest.query.get_or_404(id)
access_or_401(request.admin_unit, 'reference_request:verify') access_or_401(request.admin_unit, "reference_request:verify")
if request.review_status == EventReferenceRequestReviewStatus.verified: if request.review_status == EventReferenceRequestReviewStatus.verified:
flash(gettext('Request already verified'), 'danger') flash(gettext("Request already verified"), "danger")
return redirect(url_for('manage_admin_unit_reference_requests_incoming', id=request.admin_unit_id)) return redirect(
url_for(
"manage_admin_unit_reference_requests_incoming",
id=request.admin_unit_id,
)
)
form = ReferenceRequestReviewForm(obj=request) form = ReferenceRequestReviewForm(obj=request)
@ -34,45 +49,69 @@ def event_reference_request_review(id):
if request.review_status == EventReferenceRequestReviewStatus.verified: if request.review_status == EventReferenceRequestReviewStatus.verified:
reference = create_event_reference_for_request(request) reference = create_event_reference_for_request(request)
reference.rating = form.rating.data reference.rating = form.rating.data
msg = gettext('Request successfully updated') msg = gettext("Request successfully updated")
else: else:
msg = gettext('Reference successfully created') msg = gettext("Reference successfully created")
db.session.commit() db.session.commit()
send_reference_request_review_status_mails(request) send_reference_request_review_status_mails(request)
flash(msg, 'success') flash(msg, "success")
return redirect(url_for('manage_admin_unit_reference_requests_incoming', id=request.admin_unit_id)) return redirect(
url_for(
"manage_admin_unit_reference_requests_incoming",
id=request.admin_unit_id,
)
)
except SQLAlchemyError as e: except SQLAlchemyError as e:
db.session.rollback() db.session.rollback()
flash(handleSqlError(e), 'danger') flash(handleSqlError(e), "danger")
else: else:
flash_errors(form) flash_errors(form)
dates = EventDate.query.with_parent(request.event).filter(EventDate.start >= today).order_by(EventDate.start).all() dates = (
return render_template('reference_request/review.html', EventDate.query.with_parent(request.event)
.filter(EventDate.start >= today)
.order_by(EventDate.start)
.all()
)
return render_template(
"reference_request/review.html",
form=form, form=form,
dates=dates, dates=dates,
request=request, request=request,
event=request.event) event=request.event,
)
@app.route('/reference_request/<int:id>/review_status')
@app.route("/reference_request/<int:id>/review_status")
def event_reference_request_review_status(id): def event_reference_request_review_status(id):
request = EventReferenceRequest.query.get_or_404(id) request = EventReferenceRequest.query.get_or_404(id)
if not has_access(request.admin_unit, 'reference_request:verify') and not has_access(request.event.admin_unit, 'reference_request:create'): if not has_access(
request.admin_unit, "reference_request:verify"
) and not has_access(request.event.admin_unit, "reference_request:create"):
abort(401) abort(401)
return render_template('reference_request/review_status.html', return render_template(
"reference_request/review_status.html",
reference_request=request, reference_request=request,
event=request.event) event=request.event,
)
def send_reference_request_review_status_mails(request): def send_reference_request_review_status_mails(request):
# Benachrichtige alle Mitglieder der AdminUnit, die diesen Request erstellt hatte # Benachrichtige alle Mitglieder der AdminUnit, die diesen Request erstellt hatte
members = AdminUnitMember.query.join(User).filter(AdminUnitMember.admin_unit_id == request.event.admin_unit_id).all() members = (
AdminUnitMember.query.join(User)
.filter(AdminUnitMember.admin_unit_id == request.event.admin_unit_id)
.all()
)
for member in members: for member in members:
if has_admin_unit_member_permission(member, 'reference_request:create'): if has_admin_unit_member_permission(member, "reference_request:create"):
send_mail(member.user.email, send_mail(
gettext('Event review status updated'), member.user.email,
'reference_request_review_status_notice', gettext("Event review status updated"),
request=request) "reference_request_review_status_notice",
request=request,
)

View File

@ -2,26 +2,31 @@ from project import app
from project.views.utils import track_analytics from project.views.utils import track_analytics
from flask import url_for, render_template, request, redirect from flask import url_for, render_template, request, redirect
@app.route("/") @app.route("/")
def home(): def home():
if 'src' in request.args: if "src" in request.args:
track_analytics("home", '', request.args['src']) track_analytics("home", "", request.args["src"])
return redirect(url_for('home')) return redirect(url_for("home"))
return render_template("home.html")
return render_template('home.html')
@app.route("/example") @app.route("/example")
def example(): def example():
return render_template('example.html') return render_template("example.html")
@app.route("/impressum") @app.route("/impressum")
def impressum(): def impressum():
return render_template('impressum.html') return render_template("impressum.html")
@app.route("/datenschutz") @app.route("/datenschutz")
def datenschutz(): def datenschutz():
return render_template('datenschutz.html') return render_template("datenschutz.html")
@app.route("/developer") @app.route("/developer")
def developer(): def developer():
return render_template('developer/read.html') return render_template("developer/read.html")

View File

@ -3,12 +3,15 @@ from project.models import AdminUnitMember, AdminUnitMemberInvitation
from flask import render_template from flask import render_template
from flask_security import auth_required, current_user from flask_security import auth_required, current_user
@app.route("/profile") @app.route("/profile")
@auth_required() @auth_required()
def profile(): def profile():
admin_unit_members = AdminUnitMember.query.filter_by(user_id = current_user.id).all() admin_unit_members = AdminUnitMember.query.filter_by(user_id=current_user.id).all()
invitations = AdminUnitMemberInvitation.query.filter(AdminUnitMemberInvitation.email == current_user.email).all() invitations = AdminUnitMemberInvitation.query.filter(
AdminUnitMemberInvitation.email == current_user.email
).all()
return render_template('profile.html', return render_template(
admin_unit_members=admin_unit_members, "profile.html", admin_unit_members=admin_unit_members, invitations=invitations
invitations=invitations) )

View File

@ -4,8 +4,9 @@ from flask_babelex import gettext
from flask import request, url_for, render_template, flash, redirect, Markup from flask import request, url_for, render_template, flash, redirect, Markup
from flask_mail import Message from flask_mail import Message
def track_analytics(key, value1, value2): def track_analytics(key, value1, value2):
result = Analytics(key = key, value1 = value1) result = Analytics(key=key, value1=value1)
if value2 is not None: if value2 is not None:
result.value2 = value2 result.value2 = value2
@ -15,12 +16,14 @@ def track_analytics(key, value1, value2):
return result return result
def handleSqlError(e): def handleSqlError(e):
message = str(e.__dict__['orig']) message = str(e.__dict__["orig"])
print(message) print(message)
return message return message
def upsert_image_with_data(image, data, encoding_format = "image/jpeg"):
def upsert_image_with_data(image, data, encoding_format="image/jpeg"):
if image is None: if image is None:
image = Image() image = Image()
@ -29,6 +32,7 @@ def upsert_image_with_data(image, data, encoding_format = "image/jpeg"):
return image return image
def get_pagination_urls(pagination, **kwargs): def get_pagination_urls(pagination, **kwargs):
result = {} result = {}
@ -47,28 +51,34 @@ def get_pagination_urls(pagination, **kwargs):
return result return result
def flash_errors(form): def flash_errors(form):
for field, errors in form.errors.items(): for field, errors in form.errors.items():
for error in errors: for error in errors:
flash(gettext("Error in the %s field - %s") % ( flash(
getattr(form, field).label.text, gettext("Error in the %s field - %s")
error % (getattr(form, field).label.text, error),
), 'danger') "danger",
)
def flash_message(msg, url, link_text = None, category = 'success'):
def flash_message(msg, url, link_text=None, category="success"):
if not link_text: if not link_text:
link_text = gettext('Show') link_text = gettext("Show")
link = ' &ndash; <a href="%s">%s</a>' % (url, link_text) link = ' &ndash; <a href="%s">%s</a>' % (url, link_text)
message = Markup(msg + link) message = Markup(msg + link)
flash(message, category) flash(message, category)
def permission_missing(redirect_location): def permission_missing(redirect_location):
flash('You do not have permission for this action', 'danger') flash("You do not have permission for this action", "danger")
return redirect(redirect_location) return redirect(redirect_location)
def send_mail(recipient, subject, template, **context): def send_mail(recipient, subject, template, **context):
send_mails([recipient], subject, template, **context) send_mails([recipient], subject, template, **context)
def send_mails(recipients, subject, template, **context): def send_mails(recipients, subject, template, **context):
msg = Message(subject) msg = Message(subject)
msg.recipients = recipients msg.recipients = recipients
@ -80,4 +90,4 @@ def send_mails(recipients, subject, template, **context):
print(msg.body) print(msg.body)
return return
mail.send(msg) mail.send(msg)

Some files were not shown because too many files have changed in this diff Show More