Initial commit
This commit is contained in:
commit
52c6bdeaba
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
.idea
|
||||
venv
|
||||
*.pyc
|
||||
data/
|
||||
__pycache__
|
||||
sensitive.py
|
4
INSTALL.sh
Executable file
4
INSTALL.sh
Executable file
@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
virtualenv -p python3 venv
|
||||
source venv/bin/activate
|
||||
pip install -r requirements.txt
|
19
README.md
Normal file
19
README.md
Normal file
@ -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)_
|
27
config.py
Normal file
27
config.py
Normal file
@ -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']
|
2
data_static/Role.csv
Normal file
2
data_static/Role.csv
Normal file
@ -0,0 +1,2 @@
|
||||
name
|
||||
admin
|
|
2
data_static/User.csv
Normal file
2
data_static/User.csv
Normal file
@ -0,0 +1,2 @@
|
||||
email,password,role_names
|
||||
admin@blog.pi2.dev,__SENSITIVE__.ADMIN_PASSWORD,admin
|
|
2
data_static/_process_order
Normal file
2
data_static/_process_order
Normal file
@ -0,0 +1,2 @@
|
||||
Role
|
||||
User
|
8
init_populate.py
Normal file
8
init_populate.py
Normal file
@ -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)
|
17
manager.py
Normal file
17
manager.py
Normal file
@ -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()
|
1
migrations/README
Normal file
1
migrations/README
Normal file
@ -0,0 +1 @@
|
||||
Generic single-database configuration.
|
45
migrations/alembic.ini
Normal file
45
migrations/alembic.ini
Normal file
@ -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
|
96
migrations/env.py
Normal file
96
migrations/env.py
Normal file
@ -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()
|
24
migrations/script.py.mako
Normal file
24
migrations/script.py.mako
Normal file
@ -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"}
|
40
migrations/versions/28f9ab4fc8b0_002.py
Normal file
40
migrations/versions/28f9ab4fc8b0_002.py
Normal file
@ -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 ###
|
73
migrations/versions/d08a068031c3_001.py
Normal file
73
migrations/versions/d08a068031c3_001.py
Normal file
@ -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 ###
|
6
populate.py
Normal file
6
populate.py
Normal file
@ -0,0 +1,6 @@
|
||||
from oshipka.persistance import db
|
||||
|
||||
|
||||
def populate_db(app):
|
||||
with app.app_context():
|
||||
db.session.commit()
|
0
requirements.txt
Normal file
0
requirements.txt
Normal file
15
run.py
Normal file
15
run.py
Normal file
@ -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)
|
5
translations/babel.cfg
Normal file
5
translations/babel.cfg
Normal file
@ -0,0 +1,5 @@
|
||||
[ignore: venv/**]
|
||||
[ignore: migrations/**]
|
||||
[python: **.py]
|
||||
[jinja2: **/templates/**.html]
|
||||
extensions=jinja2.ext.autoescape,jinja2.ext.with_
|
BIN
translations/bg/LC_MESSAGES/messages.mo
Normal file
BIN
translations/bg/LC_MESSAGES/messages.mo
Normal file
Binary file not shown.
92
translations/bg/LC_MESSAGES/messages.po
Normal file
92
translations/bg/LC_MESSAGES/messages.po
Normal file
@ -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 <EMAIL@ADDRESS>, 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 <EMAIL@ADDRESS>\n"
|
||||
"Language: bg\n"
|
||||
"Language-Team: bg <LL@li.org>\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 ""
|
||||
|
BIN
translations/en/LC_MESSAGES/messages.mo
Normal file
BIN
translations/en/LC_MESSAGES/messages.mo
Normal file
Binary file not shown.
92
translations/en/LC_MESSAGES/messages.po
Normal file
92
translations/en/LC_MESSAGES/messages.po
Normal file
@ -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 <EMAIL@ADDRESS>, 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 <EMAIL@ADDRESS>\n"
|
||||
"Language: en\n"
|
||||
"Language-Team: en <LL@li.org>\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 ""
|
||||
|
91
translations/messages.pot
Normal file
91
translations/messages.pot
Normal file
@ -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 <EMAIL@ADDRESS>, 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 <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\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 ""
|
||||
|
9
webapp/app.py
Normal file
9
webapp/app.py
Normal file
@ -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")
|
2
webapp/models/__init__.py
Normal file
2
webapp/models/__init__.py
Normal file
@ -0,0 +1,2 @@
|
||||
from oshipka.persistance import db
|
||||
from webapp.models.blog_post import BlogPost
|
11
webapp/models/_blog_post.py
Normal file
11
webapp/models/_blog_post.py
Normal file
@ -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)
|
1
webapp/models/blog_post.py
Normal file
1
webapp/models/blog_post.py
Normal file
@ -0,0 +1 @@
|
||||
from webapp.models._blog_post import BlogPost
|
1
webapp/routes/__init__.py
Normal file
1
webapp/routes/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from webapp.routes.blog_post import *
|
68
webapp/routes/blog_post.py
Normal file
68
webapp/routes/blog_post.py
Normal file
@ -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'],
|
||||
)
|
71
webapp/routes/blog_post_hooks.py
Normal file
71
webapp/routes/blog_post_hooks.py
Normal file
@ -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,
|
||||
)
|
19
webapp/templates/blog_post/_create.html
Normal file
19
webapp/templates/blog_post/_create.html
Normal file
@ -0,0 +1,19 @@
|
||||
<form action="{{ url_for('create_blog_post') }}" method="post">
|
||||
<input type="hidden" name="_next" value="{{ _next or request.args.get('_next') or url_for('list_blog_post') }}"/>
|
||||
<table>
|
||||
<tr><td>
|
||||
<label for="input-blog_post-filename">{{ _("filename") }}</label>:
|
||||
</td><td>
|
||||
<input id="input-blog_post-filename"
|
||||
type="text" name="filename" autocomplete="off"
|
||||
/>
|
||||
</td></tr>
|
||||
<tr><td>
|
||||
<label for="input-blog_post-body">{{ _("body") }}</label>:
|
||||
</td><td>
|
||||
<textarea id="input-blog_post-body"
|
||||
name="body"></textarea>
|
||||
</td></tr>
|
||||
</table>
|
||||
<input type="submit">
|
||||
</form>
|
7
webapp/templates/blog_post/_get.html
Normal file
7
webapp/templates/blog_post/_get.html
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
{% if "filename" not in skip_list %}
|
||||
<li id="display-blog_post-filename"><strong>{{ _("filename") }}</strong>: {{ instance.filename }}</li>
|
||||
{% endif %}
|
||||
{% if "body" not in skip_list %}
|
||||
<li id="display-blog_post-body"><strong>{{ _("body") }}</strong>: {{ instance.body }}</li>
|
||||
{% endif %}
|
11
webapp/templates/blog_post/_list.html
Normal file
11
webapp/templates/blog_post/_list.html
Normal file
@ -0,0 +1,11 @@
|
||||
{% for instance in instances %}
|
||||
<li>
|
||||
<a href="{{ url_for('get_blog_post', uuid=instance.id) }}">
|
||||
{% include "blog_post/_title.html" %}</a>
|
||||
|
|
||||
[
|
||||
<a href="{{ url_for('update_blog_post', uuid=instance.id, _next=request.path) }}">e</a> |
|
||||
<a href="{{ url_for('delete_blog_post', uuid=instance.id, _next=request.path) }}">x</a>
|
||||
]
|
||||
</li>
|
||||
{% endfor %}
|
11
webapp/templates/blog_post/_search.html
Normal file
11
webapp/templates/blog_post/_search.html
Normal file
@ -0,0 +1,11 @@
|
||||
{% for instance in instances %}
|
||||
<li>
|
||||
<a href="{{ url_for('get_blog_post', uuid=instance.id) }}">
|
||||
{% include "blog_post/_title.html" %}</a>
|
||||
|
|
||||
[
|
||||
<a href="{{ url_for('update_blog_post', uuid=instance.id) }}">e</a> |
|
||||
<a href="{{ url_for('delete_blog_post', uuid=instance.id) }}">x</a>
|
||||
]
|
||||
</li>
|
||||
{% endfor %}
|
33
webapp/templates/blog_post/_table.html
Normal file
33
webapp/templates/blog_post/_table.html
Normal file
@ -0,0 +1,33 @@
|
||||
<table class="full-width data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
{% if "filename" not in skip_columns %}
|
||||
<th>{{ _("filename") }}</th>
|
||||
{% endif %}
|
||||
{% if "body" not in skip_columns %}
|
||||
<th>{{ _("body") }}</th>
|
||||
{% endif %}
|
||||
<th>{{ _("Actions") }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for instance in instances %}
|
||||
<tr>
|
||||
{% if "filename" not in skip_columns %}
|
||||
<td>
|
||||
{{ instance.filename }}
|
||||
</td>
|
||||
{% endif %}
|
||||
{% if "body" not in skip_columns %}
|
||||
<td>
|
||||
{{ instance.body }}
|
||||
</td>
|
||||
{% endif %}
|
||||
<td>
|
||||
<a href="{{ url_for('update_blog_post', uuid=instance.id, _next=request.path) }}">e</a> |
|
||||
<a href="{{ url_for('delete_blog_post', uuid=instance.id, _next=request.path) }}">x</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
2
webapp/templates/blog_post/_title.html
Normal file
2
webapp/templates/blog_post/_title.html
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
{{ _("BlogPost") }} {{ instance.id }}
|
20
webapp/templates/blog_post/_update.html
Normal file
20
webapp/templates/blog_post/_update.html
Normal file
@ -0,0 +1,20 @@
|
||||
<form action="{{ url_for('update_blog_post', uuid=instance.id) }}" method="post">
|
||||
<input type="hidden" name="_next" value="{{ _next or request.args.get('_next') or url_for('get_blog_post', uuid=instance.id) }}"/>
|
||||
<table>
|
||||
<tr><td>
|
||||
<label for="input-blog_post-filename">{{ _("filename") }}</label>:
|
||||
</td><td>
|
||||
<input id="input-blog_post-filename"
|
||||
value="{{ instance.filename }}"
|
||||
type="text" name="filename" autocomplete="off"
|
||||
/>
|
||||
</td></tr>
|
||||
<tr><td>
|
||||
<label for="input-blog_post-body">{{ _("body") }}</label>:
|
||||
</td><td>
|
||||
<textarea id="input-blog_post-body"
|
||||
name="body">{{ instance.body }}</textarea>
|
||||
</td></tr>
|
||||
</table>
|
||||
<input type="submit">
|
||||
</form>
|
6
webapp/templates/blog_post/create.html
Normal file
6
webapp/templates/blog_post/create.html
Normal file
@ -0,0 +1,6 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h2>{{ _("Create") }} {{_("BlogPost") }}</h2>
|
||||
{% include "blog_post/_create.html" %}
|
||||
{% endblock %}
|
9
webapp/templates/blog_post/get.html
Normal file
9
webapp/templates/blog_post/get.html
Normal file
@ -0,0 +1,9 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block content %}
|
||||
<a href="{{ url_for('list_blog_post', uuid=instance.id) }}">{{ _("list") }}</a> |
|
||||
<h2>{% include "blog_post/_title.html" %}</h2>
|
||||
<a href="{{ url_for('update_blog_post', uuid=instance.id, _next=request.path) }}">{{ _("edit") }}</a> |
|
||||
<a href="{{ url_for('delete_blog_post', uuid=instance.id) }}">{{ _("delete") }}</a>
|
||||
{% include "blog_post/_get.html" %}
|
||||
{% endblock %}
|
8
webapp/templates/blog_post/list.html
Normal file
8
webapp/templates/blog_post/list.html
Normal file
@ -0,0 +1,8 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h2>{{ _("BlogPosts") }}</h2>
|
||||
<a href="{{ url_for('create_blog_post') }}">{{ _("Create") }}</a>
|
||||
<br>
|
||||
{% include "blog_post/_list.html" %}
|
||||
{% endblock %}
|
8
webapp/templates/blog_post/search.html
Normal file
8
webapp/templates/blog_post/search.html
Normal file
@ -0,0 +1,8 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h2>{{ _("Search results for") }} {{ _("BlogPosts") }}</h2>
|
||||
<a href="{{ url_for('create_blog_post') }}">{{ _("Create") }}</a>
|
||||
<br>
|
||||
{% include "blog_post/_search.html" %}
|
||||
{% endblock %}
|
8
webapp/templates/blog_post/table.html
Normal file
8
webapp/templates/blog_post/table.html
Normal file
@ -0,0 +1,8 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h2>{{ _("BlogPosts") }}</h2>
|
||||
<a href="{{ url_for('create_blog_post') }}">{{ _("Create") }}</a>
|
||||
<br>
|
||||
{% include "blog_post/_table.html" %}
|
||||
{% endblock %}
|
6
webapp/templates/blog_post/update.html
Normal file
6
webapp/templates/blog_post/update.html
Normal file
@ -0,0 +1,6 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h2>{{ _("Edit") }} {% include "blog_post/_title.html" %}</h2>
|
||||
{% include "blog_post/_update.html" %}
|
||||
{% endblock %}
|
4
webapp/templates/home.html
Normal file
4
webapp/templates/home.html
Normal file
@ -0,0 +1,4 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block content %}
|
||||
{% endblock %}
|
223
webapp/templates/layout.html
Normal file
223
webapp/templates/layout.html
Normal file
@ -0,0 +1,223 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>{{ _("Project") }}</title>
|
||||
<style type="text/css">
|
||||
body {
|
||||
font-family: "Open Sans", Arial, sans-serif;
|
||||
color: #444;
|
||||
padding: 0 1em;
|
||||
}
|
||||
|
||||
main {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
nav {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
background: white;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media (min-width: 1400px) {
|
||||
main {
|
||||
margin: 0 150px;
|
||||
}
|
||||
|
||||
aside {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
margin: 0;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
#archive-container {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
input, textarea {
|
||||
padding: 0.5em;
|
||||
font-size: 1em;
|
||||
box-sizing: border-box;
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
input[type=number] {
|
||||
min-width: 70px;
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
input[type=checkbox] {
|
||||
min-width: 50px;
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
select {
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
textarea {
|
||||
height: 5em;
|
||||
}
|
||||
|
||||
.input-label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
blockquote > h1 {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
blockquote > h2 {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
blockquote > h3 {
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
cite:before {
|
||||
content: "\2014 ";
|
||||
}
|
||||
|
||||
cite {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.flash {
|
||||
padding: 4px;
|
||||
margin: 4px;
|
||||
top: 1em;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.flash.error {
|
||||
border: 1px solid #f22;
|
||||
background-color: #faa;
|
||||
color: #f22;
|
||||
}
|
||||
|
||||
.flash.message, .flash.info {
|
||||
border: 1px solid #28f;
|
||||
background-color: #cef;
|
||||
color: #28f;
|
||||
}
|
||||
|
||||
.flash.success {
|
||||
border: 1px solid #2f8;
|
||||
background-color: #cfe;
|
||||
color: #094;
|
||||
}
|
||||
|
||||
.danger {
|
||||
color: #f22;
|
||||
}
|
||||
|
||||
.pull-right {
|
||||
float: right;
|
||||
right: 50px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
table {
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
table tr {
|
||||
background-color: #fff;
|
||||
border-top: 1px solid #aaa;
|
||||
}
|
||||
|
||||
table tr:nth-child(2n) {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
table th, table td {
|
||||
padding: 6px 12px;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.vertical-padding {
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.video-inline {
|
||||
width: 30%;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('oshipka_bp.static', filename='css/chosen.css') }}">
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('oshipka_bp.static', filename='css/lightbox.css') }}">
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('oshipka_bp.static', filename='css/datatables.css') }}">
|
||||
{% block style %}{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
{% include "navigation.html" %}
|
||||
</nav>
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for category, message in messages %}
|
||||
<div class="flash {{ category }}">{{ message }}</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<div class="vertical-padding"></div>
|
||||
<aside>
|
||||
{% block aside %}{% endblock %}
|
||||
</aside>
|
||||
<main>
|
||||
{% if ctx and ctx.messages %}
|
||||
{% for message in ctx.messages %}
|
||||
<div class="flash {{ message.type.value }}">
|
||||
<a href="/messages/{{ message.id }}/dismiss"
|
||||
style="float:right;">x</a>
|
||||
{{ message.body|safe }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
<script src="{{ url_for('oshipka_bp.static', filename='js/jquery.js') }}"></script>
|
||||
<script src="{{ url_for('oshipka_bp.static', filename='js/lightbox.js') }}"></script>
|
||||
<script src="{{ url_for('oshipka_bp.static', filename='js/chosen.js') }}"></script>
|
||||
<script src="{{ url_for('oshipka_bp.static', filename='js/datatables.js') }}"></script>
|
||||
<script src="{{ url_for('oshipka_bp.static', filename='js/fuse.js') }}"></script>
|
||||
<script src="{{ url_for('oshipka_bp.static', filename='js/draggable.js') }}"></script>
|
||||
<script src="{{ url_for('oshipka_bp.static', filename='js/oshipka.js') }}"></script>
|
||||
<script>
|
||||
$("select").chosen({
|
||||
inherit_select_classes: true,
|
||||
});
|
||||
|
||||
lightbox.option({
|
||||
'resizeDuration': 100,
|
||||
'fadeDuration': 100,
|
||||
'imageFadeDuration': 100,
|
||||
});
|
||||
|
||||
$('.data-table').DataTable();
|
||||
</script>
|
||||
{% block script %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
9
webapp/templates/navigation.html
Normal file
9
webapp/templates/navigation.html
Normal file
@ -0,0 +1,9 @@
|
||||
<a href="{{ url_for('home') }}">{{ _("Home") }}</a> |
|
||||
<div class="pull-right">
|
||||
{% if current_user.is_authenticated %}
|
||||
<a href="#">{{ current_user.email }}</a> |
|
||||
<a href="{{ url_for('security.logout') }}">{{ _("Logout") }}</a> |
|
||||
{% else %}
|
||||
<a href="{{ url_for('security.login') }}">{{ _("Login") }}</a> |
|
||||
{% endif %}
|
||||
</div>
|
23
webapp/view_models/BlogPost.yaml
Normal file
23
webapp/view_models/BlogPost.yaml
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user