commit 52c6bdeabafdc39e71ddf7ca12e92d424629154c Author: Daniel Tsvetkov Date: Wed Jul 8 14:36:13 2020 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..71e8dbc --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.idea +venv +*.pyc +data/ +__pycache__ +sensitive.py \ No newline at end of file diff --git a/INSTALL.sh b/INSTALL.sh new file mode 100755 index 0000000..739a3c7 --- /dev/null +++ b/INSTALL.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +virtualenv -p python3 venv +source venv/bin/activate +pip install -r requirements.txt diff --git a/README.md b/README.md new file mode 100644 index 0000000..a8e1963 --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +# Project + +## Install + +``` +virtualenv -p python3 venv +source venv/bin/activate +pip install -r requirements.txt + +``` + +## Run + +``` +source venv/bin/activate +python run.py +``` + +_Powered by [oshipka](https://gitlab.com/pisquared/oshipka)_ \ No newline at end of file diff --git a/config.py b/config.py new file mode 100644 index 0000000..d0d2d8d --- /dev/null +++ b/config.py @@ -0,0 +1,27 @@ +import os + +basepath = os.path.dirname(os.path.realpath(__file__)) + +DATA_DIR = os.path.join(basepath, "data") +STATIC_DATA_DIR = os.path.join(basepath, "data_static") + +MEDIA_DIR = os.path.join(DATA_DIR, "media") + +TASKS_DIR = os.path.join(DATA_DIR, "tasks") +TASKS_IN_DIR = os.path.join(TASKS_DIR, "in") +TASKS_BUF_DIR = os.path.join(TASKS_DIR, "buf") +TASKS_PROC_DIR = os.path.join(TASKS_DIR, "proc") + +DATABASE_FILE = os.path.join(DATA_DIR, "db.sqlite") +SQLALCHEMY_DATABASE_URI = 'sqlite:///{}'.format(DATABASE_FILE) + +SEARCH_INDEX_PATH = os.path.join(DATA_DIR, "search_index") + +TEMPLATES_FOLDER = os.path.join(basepath, "webapp", "templates") +STATIC_FOLDER = os.path.join(basepath, "webapp", "static") + +MAKEDIRS = [ + DATA_DIR, STATIC_DATA_DIR, MEDIA_DIR, TASKS_DIR, TASKS_IN_DIR, TASKS_PROC_DIR, TASKS_BUF_DIR, +] + +TRANSLATION_LANGUAGES = ['en', 'bg'] diff --git a/data_static/Role.csv b/data_static/Role.csv new file mode 100644 index 0000000..fa554c4 --- /dev/null +++ b/data_static/Role.csv @@ -0,0 +1,2 @@ +name +admin \ No newline at end of file diff --git a/data_static/User.csv b/data_static/User.csv new file mode 100644 index 0000000..4206147 --- /dev/null +++ b/data_static/User.csv @@ -0,0 +1,2 @@ +email,password,role_names +admin@blog.pi2.dev,__SENSITIVE__.ADMIN_PASSWORD,admin \ No newline at end of file diff --git a/data_static/_process_order b/data_static/_process_order new file mode 100644 index 0000000..942a1ea --- /dev/null +++ b/data_static/_process_order @@ -0,0 +1,2 @@ +Role +User \ No newline at end of file diff --git a/init_populate.py b/init_populate.py new file mode 100644 index 0000000..03d709a --- /dev/null +++ b/init_populate.py @@ -0,0 +1,8 @@ +from oshipka.persistance import populate_static, init_db + +from populate import populate_db +from webapp.app import app + +init_db(app) +populate_static(app) +populate_db(app) diff --git a/manager.py b/manager.py new file mode 100644 index 0000000..9a9d944 --- /dev/null +++ b/manager.py @@ -0,0 +1,17 @@ +from flask_migrate import MigrateCommand +from flask_script import Manager + +from config import SQLALCHEMY_DATABASE_URI +from oshipka.persistance import db, migrate +from oshipka.webapp import app + +app.config["SQLALCHEMY_DATABASE_URI"] = SQLALCHEMY_DATABASE_URI +app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False +db.init_app(app) +migrate.init_app(app, db) +manager = Manager(app) +manager.add_command('db', MigrateCommand) +from webapp.models import * + +if __name__ == '__main__': + manager.run() diff --git a/migrations/README b/migrations/README new file mode 100644 index 0000000..98e4f9c --- /dev/null +++ b/migrations/README @@ -0,0 +1 @@ +Generic single-database configuration. \ No newline at end of file diff --git a/migrations/alembic.ini b/migrations/alembic.ini new file mode 100644 index 0000000..f8ed480 --- /dev/null +++ b/migrations/alembic.ini @@ -0,0 +1,45 @@ +# A generic, single database configuration. + +[alembic] +# template used to generate migration files +# file_template = %%(rev)s_%%(slug)s + +# set to 'true' to run the environment during +# the 'revision' command, regardless of autogenerate +# revision_environment = false + + +# Logging configuration +[loggers] +keys = root,sqlalchemy,alembic + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console +qualname = + +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine + +[logger_alembic] +level = INFO +handlers = +qualname = alembic + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %H:%M:%S diff --git a/migrations/env.py b/migrations/env.py new file mode 100644 index 0000000..9452179 --- /dev/null +++ b/migrations/env.py @@ -0,0 +1,96 @@ +from __future__ import with_statement + +import logging +from logging.config import fileConfig + +from sqlalchemy import engine_from_config +from sqlalchemy import pool + +from alembic import context + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config + +# Interpret the config file for Python logging. +# This line sets up loggers basically. +fileConfig(config.config_file_name) +logger = logging.getLogger('alembic.env') + +# add your model's MetaData object here +# for 'autogenerate' support +# from myapp import mymodel +# target_metadata = mymodel.Base.metadata +from flask import current_app +config.set_main_option( + 'sqlalchemy.url', + str(current_app.extensions['migrate'].db.engine.url).replace('%', '%%')) +target_metadata = current_app.extensions['migrate'].db.metadata + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + + +def run_migrations_offline(): + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = config.get_main_option("sqlalchemy.url") + context.configure( + url=url, target_metadata=target_metadata, literal_binds=True + ) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online(): + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + + # this callback is used to prevent an auto-migration from being generated + # when there are no changes to the schema + # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html + def process_revision_directives(context, revision, directives): + if getattr(config.cmd_opts, 'autogenerate', False): + script = directives[0] + if script.upgrade_ops.is_empty(): + directives[:] = [] + logger.info('No changes in schema detected.') + + connectable = engine_from_config( + config.get_section(config.config_ini_section), + prefix='sqlalchemy.', + poolclass=pool.NullPool, + ) + + with connectable.connect() as connection: + context.configure( + connection=connection, + target_metadata=target_metadata, + process_revision_directives=process_revision_directives, + **current_app.extensions['migrate'].configure_args + ) + + with context.begin_transaction(): + context.run_migrations() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/migrations/script.py.mako b/migrations/script.py.mako new file mode 100644 index 0000000..2c01563 --- /dev/null +++ b/migrations/script.py.mako @@ -0,0 +1,24 @@ +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision | comma,n} +Create Date: ${create_date} + +""" +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +# revision identifiers, used by Alembic. +revision = ${repr(up_revision)} +down_revision = ${repr(down_revision)} +branch_labels = ${repr(branch_labels)} +depends_on = ${repr(depends_on)} + + +def upgrade(): + ${upgrades if upgrades else "pass"} + + +def downgrade(): + ${downgrades if downgrades else "pass"} diff --git a/migrations/versions/28f9ab4fc8b0_002.py b/migrations/versions/28f9ab4fc8b0_002.py new file mode 100644 index 0000000..7f58913 --- /dev/null +++ b/migrations/versions/28f9ab4fc8b0_002.py @@ -0,0 +1,40 @@ +"""002 + +Revision ID: 28f9ab4fc8b0 +Revises: d08a068031c3 +Create Date: 2020-07-08 14:27:11.649888 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '28f9ab4fc8b0' +down_revision = 'd08a068031c3' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('blog_post', + sa.Column('created_dt', sa.UnicodeText(), nullable=True), + sa.Column('updated_dt', sa.UnicodeText(), nullable=True), + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('uuid', sa.Unicode(), nullable=True), + sa.Column('filename', sa.UnicodeText(), nullable=True), + sa.Column('body', sa.UnicodeText(), nullable=True), + sa.Column('user_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['user_id'], ['user.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_index(op.f('ix_blog_post_uuid'), 'blog_post', ['uuid'], unique=False) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_index(op.f('ix_blog_post_uuid'), table_name='blog_post') + op.drop_table('blog_post') + # ### end Alembic commands ### diff --git a/migrations/versions/d08a068031c3_001.py b/migrations/versions/d08a068031c3_001.py new file mode 100644 index 0000000..fb9df37 --- /dev/null +++ b/migrations/versions/d08a068031c3_001.py @@ -0,0 +1,73 @@ +"""001 + +Revision ID: d08a068031c3 +Revises: +Create Date: 2020-07-08 11:48:15.369556 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'd08a068031c3' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('role', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('uuid', sa.Unicode(), nullable=True), + sa.Column('name', sa.Unicode(), nullable=True), + sa.Column('description', sa.Unicode(), nullable=True), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('name') + ) + op.create_index(op.f('ix_role_uuid'), 'role', ['uuid'], unique=False) + op.create_table('task', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sa.Unicode(), nullable=True), + sa.Column('uuid', sa.Unicode(), nullable=True), + sa.Column('status', sa.Unicode(), nullable=True), + sa.Column('func_name', sa.Unicode(), nullable=True), + sa.Column('args', sa.Unicode(), nullable=True), + sa.Column('kwargs', sa.Unicode(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('user', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('uuid', sa.Unicode(), nullable=True), + sa.Column('email', sa.Unicode(), nullable=True), + sa.Column('password', sa.Unicode(), nullable=True), + sa.Column('active', sa.Boolean(), nullable=True), + sa.Column('confirmed_at', sa.DateTime(), nullable=True), + sa.Column('timezone', sa.String(), nullable=True), + sa.Column('tz_offset_seconds', sa.Integer(), nullable=True), + sa.Column('locale', sa.String(length=4), nullable=True), + sa.Column('name', sa.Unicode(), nullable=True), + sa.Column('profile_image_url', sa.String(), nullable=True), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('email') + ) + op.create_index(op.f('ix_user_uuid'), 'user', ['uuid'], unique=False) + op.create_table('roles_users', + sa.Column('user_id', sa.Integer(), nullable=True), + sa.Column('role_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['role_id'], ['role.id'], ), + sa.ForeignKeyConstraint(['user_id'], ['user.id'], ) + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('roles_users') + op.drop_index(op.f('ix_user_uuid'), table_name='user') + op.drop_table('user') + op.drop_table('task') + op.drop_index(op.f('ix_role_uuid'), table_name='role') + op.drop_table('role') + # ### end Alembic commands ### diff --git a/populate.py b/populate.py new file mode 100644 index 0000000..2db3117 --- /dev/null +++ b/populate.py @@ -0,0 +1,6 @@ +from oshipka.persistance import db + + +def populate_db(app): + with app.app_context(): + db.session.commit() \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e69de29 diff --git a/run.py b/run.py new file mode 100644 index 0000000..1d516f8 --- /dev/null +++ b/run.py @@ -0,0 +1,15 @@ +from config import TEMPLATES_FOLDER, STATIC_FOLDER +from oshipka.persistance import populate_static, init_db + +from populate import populate_db +from webapp.app import app + +if init_db(app): + populate_static(app) + populate_db(app) + +app.template_folder = TEMPLATES_FOLDER +app.static_folder = STATIC_FOLDER + +if __name__ == "__main__": + app.run(debug=True) diff --git a/translations/babel.cfg b/translations/babel.cfg new file mode 100644 index 0000000..d3f93b0 --- /dev/null +++ b/translations/babel.cfg @@ -0,0 +1,5 @@ +[ignore: venv/**] +[ignore: migrations/**] +[python: **.py] +[jinja2: **/templates/**.html] +extensions=jinja2.ext.autoescape,jinja2.ext.with_ \ No newline at end of file diff --git a/translations/bg/LC_MESSAGES/messages.mo b/translations/bg/LC_MESSAGES/messages.mo new file mode 100644 index 0000000..268cb18 Binary files /dev/null and b/translations/bg/LC_MESSAGES/messages.mo differ diff --git a/translations/bg/LC_MESSAGES/messages.po b/translations/bg/LC_MESSAGES/messages.po new file mode 100644 index 0000000..3bf42cd --- /dev/null +++ b/translations/bg/LC_MESSAGES/messages.po @@ -0,0 +1,92 @@ +# Bulgarian translations for PROJECT. +# Copyright (C) 2020 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , 2020. +# +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2020-07-08 14:25+0200\n" +"PO-Revision-Date: 2020-07-08 14:25+0200\n" +"Last-Translator: FULL NAME \n" +"Language: bg\n" +"Language-Team: bg \n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.8.0\n" + +#: webapp/templates/layout.html:7 +msgid "Project" +msgstr "" + +#: webapp/templates/navigation.html:1 +msgid "Home" +msgstr "" + +#: webapp/templates/navigation.html:5 +msgid "Logout" +msgstr "" + +#: webapp/templates/navigation.html:7 +msgid "Login" +msgstr "" + +#: webapp/templates/blog_post/_create.html:5 +#: webapp/templates/blog_post/_get.html:3 +#: webapp/templates/blog_post/_table.html:5 +#: webapp/templates/blog_post/_update.html:5 +msgid "filename" +msgstr "" + +#: webapp/templates/blog_post/_create.html:12 +#: webapp/templates/blog_post/_get.html:6 +#: webapp/templates/blog_post/_table.html:8 +#: webapp/templates/blog_post/_update.html:13 +msgid "body" +msgstr "" + +#: webapp/templates/blog_post/_table.html:10 +msgid "Actions" +msgstr "" + +#: webapp/templates/blog_post/_title.html:2 +#: webapp/templates/blog_post/create.html:4 +msgid "BlogPost" +msgstr "" + +#: webapp/templates/blog_post/create.html:4 +#: webapp/templates/blog_post/list.html:5 +#: webapp/templates/blog_post/search.html:5 +#: webapp/templates/blog_post/table.html:5 +msgid "Create" +msgstr "" + +#: webapp/templates/blog_post/get.html:4 +msgid "list" +msgstr "" + +#: webapp/templates/blog_post/get.html:6 +msgid "edit" +msgstr "" + +#: webapp/templates/blog_post/get.html:7 +msgid "delete" +msgstr "" + +#: webapp/templates/blog_post/list.html:4 +#: webapp/templates/blog_post/search.html:4 +#: webapp/templates/blog_post/table.html:4 +msgid "BlogPosts" +msgstr "" + +#: webapp/templates/blog_post/search.html:4 +msgid "Search results for" +msgstr "" + +#: webapp/templates/blog_post/update.html:4 +msgid "Edit" +msgstr "" + diff --git a/translations/en/LC_MESSAGES/messages.mo b/translations/en/LC_MESSAGES/messages.mo new file mode 100644 index 0000000..1453697 Binary files /dev/null and b/translations/en/LC_MESSAGES/messages.mo differ diff --git a/translations/en/LC_MESSAGES/messages.po b/translations/en/LC_MESSAGES/messages.po new file mode 100644 index 0000000..853968a --- /dev/null +++ b/translations/en/LC_MESSAGES/messages.po @@ -0,0 +1,92 @@ +# English translations for PROJECT. +# Copyright (C) 2020 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , 2020. +# +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2020-07-08 14:25+0200\n" +"PO-Revision-Date: 2020-07-08 14:25+0200\n" +"Last-Translator: FULL NAME \n" +"Language: en\n" +"Language-Team: en \n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.8.0\n" + +#: webapp/templates/layout.html:7 +msgid "Project" +msgstr "" + +#: webapp/templates/navigation.html:1 +msgid "Home" +msgstr "" + +#: webapp/templates/navigation.html:5 +msgid "Logout" +msgstr "" + +#: webapp/templates/navigation.html:7 +msgid "Login" +msgstr "" + +#: webapp/templates/blog_post/_create.html:5 +#: webapp/templates/blog_post/_get.html:3 +#: webapp/templates/blog_post/_table.html:5 +#: webapp/templates/blog_post/_update.html:5 +msgid "filename" +msgstr "" + +#: webapp/templates/blog_post/_create.html:12 +#: webapp/templates/blog_post/_get.html:6 +#: webapp/templates/blog_post/_table.html:8 +#: webapp/templates/blog_post/_update.html:13 +msgid "body" +msgstr "" + +#: webapp/templates/blog_post/_table.html:10 +msgid "Actions" +msgstr "" + +#: webapp/templates/blog_post/_title.html:2 +#: webapp/templates/blog_post/create.html:4 +msgid "BlogPost" +msgstr "" + +#: webapp/templates/blog_post/create.html:4 +#: webapp/templates/blog_post/list.html:5 +#: webapp/templates/blog_post/search.html:5 +#: webapp/templates/blog_post/table.html:5 +msgid "Create" +msgstr "" + +#: webapp/templates/blog_post/get.html:4 +msgid "list" +msgstr "" + +#: webapp/templates/blog_post/get.html:6 +msgid "edit" +msgstr "" + +#: webapp/templates/blog_post/get.html:7 +msgid "delete" +msgstr "" + +#: webapp/templates/blog_post/list.html:4 +#: webapp/templates/blog_post/search.html:4 +#: webapp/templates/blog_post/table.html:4 +msgid "BlogPosts" +msgstr "" + +#: webapp/templates/blog_post/search.html:4 +msgid "Search results for" +msgstr "" + +#: webapp/templates/blog_post/update.html:4 +msgid "Edit" +msgstr "" + diff --git a/translations/messages.pot b/translations/messages.pot new file mode 100644 index 0000000..e6445bf --- /dev/null +++ b/translations/messages.pot @@ -0,0 +1,91 @@ +# Translations template for PROJECT. +# Copyright (C) 2020 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , 2020. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2020-07-08 14:25+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.8.0\n" + +#: webapp/templates/layout.html:7 +msgid "Project" +msgstr "" + +#: webapp/templates/navigation.html:1 +msgid "Home" +msgstr "" + +#: webapp/templates/navigation.html:5 +msgid "Logout" +msgstr "" + +#: webapp/templates/navigation.html:7 +msgid "Login" +msgstr "" + +#: webapp/templates/blog_post/_create.html:5 +#: webapp/templates/blog_post/_get.html:3 +#: webapp/templates/blog_post/_table.html:5 +#: webapp/templates/blog_post/_update.html:5 +msgid "filename" +msgstr "" + +#: webapp/templates/blog_post/_create.html:12 +#: webapp/templates/blog_post/_get.html:6 +#: webapp/templates/blog_post/_table.html:8 +#: webapp/templates/blog_post/_update.html:13 +msgid "body" +msgstr "" + +#: webapp/templates/blog_post/_table.html:10 +msgid "Actions" +msgstr "" + +#: webapp/templates/blog_post/_title.html:2 +#: webapp/templates/blog_post/create.html:4 +msgid "BlogPost" +msgstr "" + +#: webapp/templates/blog_post/create.html:4 +#: webapp/templates/blog_post/list.html:5 +#: webapp/templates/blog_post/search.html:5 +#: webapp/templates/blog_post/table.html:5 +msgid "Create" +msgstr "" + +#: webapp/templates/blog_post/get.html:4 +msgid "list" +msgstr "" + +#: webapp/templates/blog_post/get.html:6 +msgid "edit" +msgstr "" + +#: webapp/templates/blog_post/get.html:7 +msgid "delete" +msgstr "" + +#: webapp/templates/blog_post/list.html:4 +#: webapp/templates/blog_post/search.html:4 +#: webapp/templates/blog_post/table.html:4 +msgid "BlogPosts" +msgstr "" + +#: webapp/templates/blog_post/search.html:4 +msgid "Search results for" +msgstr "" + +#: webapp/templates/blog_post/update.html:4 +msgid "Edit" +msgstr "" + diff --git a/webapp/app.py b/webapp/app.py new file mode 100644 index 0000000..9b95cd6 --- /dev/null +++ b/webapp/app.py @@ -0,0 +1,9 @@ +from flask import render_template + +from webapp.routes import * +from oshipka.webapp import app + + +@app.route('/') +def home(): + return render_template("home.html") diff --git a/webapp/models/__init__.py b/webapp/models/__init__.py new file mode 100644 index 0000000..2f0e777 --- /dev/null +++ b/webapp/models/__init__.py @@ -0,0 +1,2 @@ +from oshipka.persistance import db +from webapp.models.blog_post import BlogPost diff --git a/webapp/models/_blog_post.py b/webapp/models/_blog_post.py new file mode 100644 index 0000000..49c701e --- /dev/null +++ b/webapp/models/_blog_post.py @@ -0,0 +1,11 @@ +from oshipka.persistance import db, ModelController, index_service, LiberalBoolean, Ownable, Datable + + +class BlogPost(db.Model, ModelController, Ownable, Datable): + __searchable__ = ['body', ] + + filename = db.Column(db.UnicodeText,) + body = db.Column(db.UnicodeText,) + + +index_service.searchables.append(BlogPost) diff --git a/webapp/models/blog_post.py b/webapp/models/blog_post.py new file mode 100644 index 0000000..3fd573f --- /dev/null +++ b/webapp/models/blog_post.py @@ -0,0 +1 @@ +from webapp.models._blog_post import BlogPost \ No newline at end of file diff --git a/webapp/routes/__init__.py b/webapp/routes/__init__.py new file mode 100644 index 0000000..0db7492 --- /dev/null +++ b/webapp/routes/__init__.py @@ -0,0 +1 @@ +from webapp.routes.blog_post import * diff --git a/webapp/routes/blog_post.py b/webapp/routes/blog_post.py new file mode 100644 index 0000000..f5c2872 --- /dev/null +++ b/webapp/routes/blog_post.py @@ -0,0 +1,68 @@ +""" +!!!AUTOGENERATED: DO NOT EDIT!!! + +Edit the hooks in webapp/routes/blog_post_hooks.py instead +""" + +from oshipka.webapp import app +from oshipka.webapp.views import ModelView +from webapp.models import BlogPost +from webapp.routes.blog_post_hooks import * + +blog_post = ModelView(app, BlogPost) + +blog_post.register_verb(view_context=get_view_context, + verb="get", + methods=['GET'], + per_item=True, + is_login_required=False, + the_roles_required=[], + ) + +blog_post.register_verb(view_context=list_view_context, + verb="list", + methods=['GET'], + per_item=False, + is_login_required=False, + the_roles_required=[], + ) + +blog_post.register_verb(view_context=table_view_context, + verb="table", + methods=['GET'], + per_item=False, + is_login_required=False, + the_roles_required=[], + ) + +blog_post.register_verb(view_context=search_view_context, + verb="search", + methods=['GET'], + per_item=False, + is_login_required=False, + the_roles_required=[], + ) + +blog_post.register_verb(view_context=create_view_context, + verb="create", + methods=['GET', 'POST'], + per_item=False, + is_login_required=True, + the_roles_required=['admin'], + ) + +blog_post.register_verb(view_context=update_view_context, + verb="update", + methods=['GET', 'POST'], + per_item=True, + is_login_required=True, + the_roles_required=['admin'], + ) + +blog_post.register_verb(view_context=delete_view_context, + verb="delete", + methods=['GET', 'POST'], + per_item=True, + is_login_required=True, + the_roles_required=['admin'], + ) diff --git a/webapp/routes/blog_post_hooks.py b/webapp/routes/blog_post_hooks.py new file mode 100644 index 0000000..164439a --- /dev/null +++ b/webapp/routes/blog_post_hooks.py @@ -0,0 +1,71 @@ +from oshipka.webapp.views import ViewContext, default_get_args_func, default_get_func, default_list_func, \ + default_get_form_func, default_create_func, default_update_func, default_delete_func, default_search_func + + +def get_template(vc): + vc.template = "{}/get.html".format(vc.model_view.model_name) + + +def list_template(vc): + vc.template = "{}/list.html".format(vc.model_view.model_name) + + +def table_template(vc): + vc.template = "{}/table.html".format(vc.model_view.model_name) + + +def search_template(vc): + vc.template = "{}/search.html".format(vc.model_view.model_name) + + +def create_template(vc): + vc.template = "{}/create.html".format(vc.model_view.model_name) + + +def update_template(vc): + vc.template = "{}/update.html".format(vc.model_view.model_name) + + +def delete_template(vc): + vc.template = "delete_instance.html".format(vc.model_view.model_name) + + +get_view_context = ViewContext( + filter_func=default_get_func, + template_func=get_template, +) + +list_view_context = ViewContext( + filter_func=default_list_func, + template_func=list_template, +) + +table_view_context = ViewContext( + filter_func=default_list_func, + template_func=table_template, +) + +search_view_context = ViewContext( + filter_func=default_search_func, + template_func=list_template, +) + +create_view_context = ViewContext( + args_get_func=default_get_form_func, + template_func=create_template, + execute_func=default_create_func, +) + +update_view_context = ViewContext( + args_get_func=default_get_form_func, + filter_func=default_get_func, + template_func=update_template, + execute_func=default_update_func, +) + +delete_view_context = ViewContext( + args_get_func=default_get_form_func, + filter_func=default_get_func, + template_func=delete_template, + execute_func=default_delete_func, +) diff --git a/webapp/templates/blog_post/_create.html b/webapp/templates/blog_post/_create.html new file mode 100644 index 0000000..930364f --- /dev/null +++ b/webapp/templates/blog_post/_create.html @@ -0,0 +1,19 @@ +
+ + + + +
+ : + + +
+ : + + +
+ +
\ No newline at end of file diff --git a/webapp/templates/blog_post/_get.html b/webapp/templates/blog_post/_get.html new file mode 100644 index 0000000..b97fc06 --- /dev/null +++ b/webapp/templates/blog_post/_get.html @@ -0,0 +1,7 @@ + +{% if "filename" not in skip_list %} +
  • {{ _("filename") }}: {{ instance.filename }}
  • +{% endif %} +{% if "body" not in skip_list %} +
  • {{ _("body") }}: {{ instance.body }}
  • +{% endif %} \ No newline at end of file diff --git a/webapp/templates/blog_post/_list.html b/webapp/templates/blog_post/_list.html new file mode 100644 index 0000000..e241aa7 --- /dev/null +++ b/webapp/templates/blog_post/_list.html @@ -0,0 +1,11 @@ +{% for instance in instances %} +
  • + + {% include "blog_post/_title.html" %} + | + [ + e | + x + ] +
  • +{% endfor %} \ No newline at end of file diff --git a/webapp/templates/blog_post/_search.html b/webapp/templates/blog_post/_search.html new file mode 100644 index 0000000..e4eaf26 --- /dev/null +++ b/webapp/templates/blog_post/_search.html @@ -0,0 +1,11 @@ +{% for instance in instances %} +
  • + + {% include "blog_post/_title.html" %} + | + [ + e | + x + ] +
  • +{% endfor %} \ No newline at end of file diff --git a/webapp/templates/blog_post/_table.html b/webapp/templates/blog_post/_table.html new file mode 100644 index 0000000..c7bd915 --- /dev/null +++ b/webapp/templates/blog_post/_table.html @@ -0,0 +1,33 @@ + + + + {% if "filename" not in skip_columns %} + + {% endif %} + {% if "body" not in skip_columns %} + + {% endif %} + + + + + {% for instance in instances %} + + {% if "filename" not in skip_columns %} + + {% endif %} + {% if "body" not in skip_columns %} + + {% endif %} + + + {% endfor %} + +
    {{ _("filename") }}{{ _("body") }}{{ _("Actions") }}
    + {{ instance.filename }} + + {{ instance.body }} + + e | + x +
    \ No newline at end of file diff --git a/webapp/templates/blog_post/_title.html b/webapp/templates/blog_post/_title.html new file mode 100644 index 0000000..5876a49 --- /dev/null +++ b/webapp/templates/blog_post/_title.html @@ -0,0 +1,2 @@ + + {{ _("BlogPost") }} {{ instance.id }} \ No newline at end of file diff --git a/webapp/templates/blog_post/_update.html b/webapp/templates/blog_post/_update.html new file mode 100644 index 0000000..a01a453 --- /dev/null +++ b/webapp/templates/blog_post/_update.html @@ -0,0 +1,20 @@ +
    + + + + +
    + : + + +
    + : + + +
    + +
    \ No newline at end of file diff --git a/webapp/templates/blog_post/create.html b/webapp/templates/blog_post/create.html new file mode 100644 index 0000000..7ccd972 --- /dev/null +++ b/webapp/templates/blog_post/create.html @@ -0,0 +1,6 @@ +{% extends "layout.html" %} + +{% block content %} +

    {{ _("Create") }} {{_("BlogPost") }}

    + {% include "blog_post/_create.html" %} +{% endblock %} \ No newline at end of file diff --git a/webapp/templates/blog_post/get.html b/webapp/templates/blog_post/get.html new file mode 100644 index 0000000..ac1146f --- /dev/null +++ b/webapp/templates/blog_post/get.html @@ -0,0 +1,9 @@ +{% extends "layout.html" %} + +{% block content %} + {{ _("list") }} | +

    {% include "blog_post/_title.html" %}

    + {{ _("edit") }} | + {{ _("delete") }} + {% include "blog_post/_get.html" %} +{% endblock %} \ No newline at end of file diff --git a/webapp/templates/blog_post/list.html b/webapp/templates/blog_post/list.html new file mode 100644 index 0000000..8d60117 --- /dev/null +++ b/webapp/templates/blog_post/list.html @@ -0,0 +1,8 @@ +{% extends "layout.html" %} + +{% block content %} +

    {{ _("BlogPosts") }}

    + {{ _("Create") }} +
    + {% include "blog_post/_list.html" %} +{% endblock %} \ No newline at end of file diff --git a/webapp/templates/blog_post/search.html b/webapp/templates/blog_post/search.html new file mode 100644 index 0000000..45ef8f6 --- /dev/null +++ b/webapp/templates/blog_post/search.html @@ -0,0 +1,8 @@ +{% extends "layout.html" %} + +{% block content %} +

    {{ _("Search results for") }} {{ _("BlogPosts") }}

    + {{ _("Create") }} +
    + {% include "blog_post/_search.html" %} +{% endblock %} \ No newline at end of file diff --git a/webapp/templates/blog_post/table.html b/webapp/templates/blog_post/table.html new file mode 100644 index 0000000..f2f575c --- /dev/null +++ b/webapp/templates/blog_post/table.html @@ -0,0 +1,8 @@ +{% extends "layout.html" %} + +{% block content %} +

    {{ _("BlogPosts") }}

    + {{ _("Create") }} +
    + {% include "blog_post/_table.html" %} +{% endblock %} \ No newline at end of file diff --git a/webapp/templates/blog_post/update.html b/webapp/templates/blog_post/update.html new file mode 100644 index 0000000..78365fb --- /dev/null +++ b/webapp/templates/blog_post/update.html @@ -0,0 +1,6 @@ +{% extends "layout.html" %} + +{% block content %} +

    {{ _("Edit") }} {% include "blog_post/_title.html" %}

    + {% include "blog_post/_update.html" %} +{% endblock %} \ No newline at end of file diff --git a/webapp/templates/home.html b/webapp/templates/home.html new file mode 100644 index 0000000..e800799 --- /dev/null +++ b/webapp/templates/home.html @@ -0,0 +1,4 @@ +{% extends "layout.html" %} + +{% block content %} +{% endblock %} \ No newline at end of file diff --git a/webapp/templates/layout.html b/webapp/templates/layout.html new file mode 100644 index 0000000..3a0da28 --- /dev/null +++ b/webapp/templates/layout.html @@ -0,0 +1,223 @@ + + + + + + + {{ _("Project") }} + + + + + {% block style %}{% endblock %} + + + +{% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} + {% for category, message in messages %} +
    {{ message }}
    + {% endfor %} + {% endif %} +{% endwith %} +
    + +
    + {% if ctx and ctx.messages %} + {% for message in ctx.messages %} +
    + x + {{ message.body|safe }} +
    + {% endfor %} + {% endif %} + {% block content %}{% endblock %} +
    + + + + + + + + +{% block script %}{% endblock %} + + diff --git a/webapp/templates/navigation.html b/webapp/templates/navigation.html new file mode 100644 index 0000000..06ea396 --- /dev/null +++ b/webapp/templates/navigation.html @@ -0,0 +1,9 @@ +{{ _("Home") }} | +
    + {% if current_user.is_authenticated %} + {{ current_user.email }} | + {{ _("Logout") }} | + {% else %} + {{ _("Login") }} | + {% endif %} +
    \ No newline at end of file diff --git a/webapp/view_models/BlogPost.yaml b/webapp/view_models/BlogPost.yaml new file mode 100644 index 0000000..c70302b --- /dev/null +++ b/webapp/view_models/BlogPost.yaml @@ -0,0 +1,23 @@ +name: BlogPost +searchable: + - body +interits: + - Ownable + - Datable +access: + - verb: all + login_required: true + roles_required: + - admin + - verb: get + login_required: false + - verb: list + login_required: false + - verb: table + login_required: false + - verb: search + login_required: false +columns: + - name: filename + - name: body + type: long_text \ No newline at end of file diff --git a/worker.py b/worker.py new file mode 100644 index 0000000..f69e1c7 --- /dev/null +++ b/worker.py @@ -0,0 +1,13 @@ +from oshipka import worker + +from oshipka.persistance import populate_static, init_db + +from populate import populate_db +from webapp.app import app + +if init_db(app): + populate_static(app) + populate_db(app) + +if __name__ == "__main__": + worker.main()