Compare commits

...

3 Commits

Author SHA1 Message Date
Ferdinand Thiessen 74ceb1b1f3 [cli] Added install command to install the database and all plugins
Signed-off-by: Ferdinand Thiessen <rpm@fthiessen.de>
2022-07-31 15:48:47 +02:00
Ferdinand Thiessen 6c73a63eb5 [cli] Make sure plugin permissions are installed
Signed-off-by: Ferdinand Thiessen <rpm@fthiessen.de>
2022-07-31 15:45:37 +02:00
Ferdinand Thiessen 3d6b37f0a5 [plugins] Add missing IDs and fix initial migration file
Signed-off-by: Ferdinand Thiessen <rpm@fthiessen.de>
2022-07-31 13:22:11 +02:00
12 changed files with 82 additions and 21 deletions

View File

@ -50,10 +50,16 @@ If not you need to create user and database manually do (or similar on Windows):
) | sudo mysql ) | sudo mysql
Then you can install the database tables, this will update all tables from core + all enabled plugins. Then you can install the database tables, this will update all tables from core + all enabled plugins.
*Hint:* The same command can be later used to upgrade the database after plugins or core are updated. And also install all enabled plugins:
$ flaschengeist install
*Hint:* To only install the database tables, or upgrade the database after plugins or core are updated later
you can use this command:
$ flaschengeist db upgrade heads $ flaschengeist db upgrade heads
## Plugins ## Plugins
To only upgrade one plugin (for example the `events` plugin): To only upgrade one plugin (for example the `events` plugin):
@ -88,6 +94,7 @@ with the difference of the main logger will be forced to output to `stderr` and
of the CLI will override the logging level you have configured for the main logger. of the CLI will override the logging level you have configured for the main logger.
$ flaschengeist run $ flaschengeist run
or with debug messages: or with debug messages:
$ flaschengeist run --debug $ flaschengeist run --debug

View File

@ -0,0 +1,4 @@
from pathlib import Path
alembic_migrations = str(Path(__file__).resolve().parent / "migrations")

View File

@ -18,14 +18,21 @@ depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### op.create_table(
"plugin_setting",
sa.Column("id", flaschengeist.models.Serial(), nullable=False),
sa.Column("plugin", sa.String(length=127), nullable=True),
sa.Column("name", sa.String(length=127), nullable=False),
sa.Column("value", sa.PickleType(protocol=4), nullable=True),
sa.PrimaryKeyConstraint("id", name=op.f("pk_plugin_setting")),
)
op.create_table( op.create_table(
"image", "image",
sa.Column("id", flaschengeist.models.Serial(), nullable=False), sa.Column("id", flaschengeist.models.Serial(), nullable=False),
sa.Column("filename_", sa.String(length=127), nullable=False), sa.Column("filename", sa.String(length=255), nullable=False),
sa.Column("mimetype_", sa.String(length=30), nullable=False), sa.Column("mimetype", sa.String(length=127), nullable=False),
sa.Column("thumbnail_", sa.String(length=127), nullable=True), sa.Column("thumbnail", sa.String(length=255), nullable=True),
sa.Column("path_", sa.String(length=127), nullable=True), sa.Column("path", sa.String(length=255), nullable=True),
sa.PrimaryKeyConstraint("id", name=op.f("pk_image")), sa.PrimaryKeyConstraint("id", name=op.f("pk_image")),
) )
op.create_table( op.create_table(

View File

@ -88,12 +88,14 @@ def main(*args, **kwargs):
from .export_cmd import export from .export_cmd import export
from .docs_cmd import docs from .docs_cmd import docs
from .run_cmd import run from .run_cmd import run
from .install_cmd import install
# Override logging level # Override logging level
environ.setdefault("FG_LOGGING", logging.getLevelName(LOGGING_MAX)) environ.setdefault("FG_LOGGING", logging.getLevelName(LOGGING_MAX))
cli.add_command(export) cli.add_command(export)
cli.add_command(docs) cli.add_command(docs)
cli.add_command(install)
cli.add_command(plugin) cli.add_command(plugin)
cli.add_command(run) cli.add_command(run)
cli(*args, **kwargs) cli(*args, **kwargs)

View File

@ -0,0 +1,20 @@
import click
from click.decorators import pass_context
from flask.cli import with_appcontext
from flask_migrate import upgrade
from flaschengeist.alembic import alembic_migrations
from flaschengeist.cli.plugin_cmd import install_plugin_command
from flaschengeist.utils.hook import Hook
@click.command()
@with_appcontext
@pass_context
@Hook("plugins.installed")
def install(ctx):
# Install database
upgrade(alembic_migrations, revision="heads")
# Install plugins
install_plugin_command(ctx, [], True)

View File

@ -4,7 +4,9 @@ from flask import current_app
from flask.cli import with_appcontext from flask.cli import with_appcontext
from importlib_metadata import EntryPoint, entry_points from importlib_metadata import EntryPoint, entry_points
from flaschengeist.database import db
from flaschengeist.config import config from flaschengeist.config import config
from flaschengeist.models.user import Permission
@click.group() @click.group()
@ -12,12 +14,7 @@ def plugin():
pass pass
@plugin.command() def install_plugin_command(ctx, plugin, all):
@click.argument("plugin", nargs=-1, type=str)
@click.option("--all", help="Install all enabled plugins", is_flag=True)
@with_appcontext
@pass_context
def install(ctx, plugin, all):
"""Install one or more plugins""" """Install one or more plugins"""
if not all and len(plugin) == 0: if not all and len(plugin) == 0:
ctx.fail("At least one plugin must be specified, or use `--all` flag.") ctx.fail("At least one plugin must be specified, or use `--all` flag.")
@ -31,10 +28,30 @@ def install(ctx, plugin, all):
for p in plugins: for p in plugins:
name = p.id.split(".")[-1] name = p.id.split(".")[-1]
click.echo(f"Installing {name}{'.'*(20-len(name))}", nl=False) click.echo(f"Installing {name}{'.'*(20-len(name))}", nl=False)
# Install permissions
if p.permissions:
cur_perm = set(x.name for x in Permission.query.filter(Permission.name.in_(p.permissions)).all())
all_perm = set(p.permissions)
add = all_perm - cur_perm
if add:
db.session.bulk_save_objects([Permission(name=x) for x in all_perm])
db.session.commit()
# Custom installation steps
p.install() p.install()
click.secho(" ok", fg="green") click.secho(" ok", fg="green")
@plugin.command()
@click.argument("plugin", nargs=-1, type=str)
@click.option("--all", help="Install all enabled plugins", is_flag=True)
@with_appcontext
@pass_context
def install(ctx, plugin, all):
"""Install one or more plugins"""
return install_plugin_command(ctx, plugin, all)
@plugin.command() @plugin.command()
@click.argument("plugin", nargs=-1, type=str) @click.argument("plugin", nargs=-1, type=str)
@with_appcontext @with_appcontext

View File

@ -9,11 +9,11 @@ from ..database import db
class Image(db.Model, ModelSerializeMixin): class Image(db.Model, ModelSerializeMixin):
__tablename__ = "image" __tablename__ = "image"
id: int = db.Column("id", Serial, primary_key=True) id: int = db.Column(Serial, primary_key=True)
filename_: str = db.Column(db.String(127), nullable=False) filename_: str = db.Column("filename", db.String(255), nullable=False)
mimetype_: str = db.Column(db.String(30), nullable=False) mimetype_: str = db.Column("mimetype", db.String(127), nullable=False)
thumbnail_: str = db.Column(db.String(127)) thumbnail_: str = db.Column("thumbnail", db.String(255))
path_: str = db.Column(db.String(127)) path_: str = db.Column("path", db.String(255))
def open(self): def open(self):
return open(self.path_, "rb") return open(self.path_, "rb")

View File

@ -8,6 +8,6 @@ from ..database import db
class _PluginSetting(db.Model): class _PluginSetting(db.Model):
__tablename__ = "plugin_setting" __tablename__ = "plugin_setting"
id = db.Column("id", Serial, primary_key=True) id = db.Column("id", Serial, primary_key=True)
plugin: str = db.Column(db.String(30)) plugin: str = db.Column(db.String(127))
name: str = db.Column(db.String(30), nullable=False) name: str = db.Column(db.String(127), nullable=False)
value: Any = db.Column(db.PickleType(protocol=4)) value: Any = db.Column(db.PickleType(protocol=4))

View File

@ -19,7 +19,7 @@ class AuthPlain(AuthPlugin):
def install(self): def install(self):
plugins_installed(self.post_install) plugins_installed(self.post_install)
def post_install(self, **kwargs): def post_install(self, *args, **kwargs):
if User.query.filter(User.deleted == False).count() == 0: if User.query.filter(User.deleted == False).count() == 0:
logger.info("Installing admin user") logger.info("Installing admin user")
role = Role.query.filter(Role.name == "Superuser").first() role = Role.query.filter(Role.name == "Superuser").first()

View File

@ -16,6 +16,7 @@ from . import permissions
class RolesPlugin(Plugin): class RolesPlugin(Plugin):
id = "roles"
blueprint = Blueprint("roles", __name__) blueprint = Blueprint("roles", __name__)
permissions = permissions.permissions permissions = permissions.permissions

View File

@ -39,6 +39,8 @@ def scheduled(id: str, replace=False, **kwargs):
class SchedulerPlugin(Plugin): class SchedulerPlugin(Plugin):
id = "scheduler"
def __init__(self, entry_point, config=None): def __init__(self, entry_point, config=None):
super().__init__(entry_point, config) super().__init__(entry_point, config)
self.blueprint = Blueprint(self.name, __name__) self.blueprint = Blueprint(self.name, __name__)

View File

@ -18,6 +18,7 @@ from flaschengeist.utils.datetime import from_iso_format
class UsersPlugin(Plugin): class UsersPlugin(Plugin):
id = "users"
blueprint = Blueprint("users", __name__) blueprint = Blueprint("users", __name__)
permissions = permissions.permissions permissions = permissions.permissions
@ -104,7 +105,7 @@ def frontend(userid, current_session):
raise Forbidden raise Forbidden
if request.method == "POST": if request.method == "POST":
if request.content_length > 1024**2: if request.content_length > 1024 ** 2:
raise BadRequest raise BadRequest
current_session.user_.set_attribute("frontend", request.get_json()) current_session.user_.set_attribute("frontend", request.get_json())
return no_content() return no_content()