[plugins][cli] Fix initial migration file + Make sure plugin permissions are installed
Signed-off-by: Ferdinand Thiessen <rpm@fthiessen.de>
This commit is contained in:
parent
573bea2da0
commit
f1d6b6a2f2
|
@ -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(
|
||||||
|
|
|
@ -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,6 +14,35 @@ def plugin():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def install_plugin_command(ctx, plugin, all):
|
||||||
|
"""Install one or more plugins"""
|
||||||
|
if not all and len(plugin) == 0:
|
||||||
|
ctx.fail("At least one plugin must be specified, or use `--all` flag.")
|
||||||
|
|
||||||
|
if all:
|
||||||
|
plugins = current_app.config["FG_PLUGINS"]
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
plugins = {plugin_name: current_app.config["FG_PLUGINS"][plugin_name] for plugin_name in plugin}
|
||||||
|
except KeyError as e:
|
||||||
|
ctx.fail(f"Invalid plugin name, could not find >{e.args[0]}<")
|
||||||
|
|
||||||
|
for name, plugin in plugins.items():
|
||||||
|
click.echo(f"Installing {name}{'.'*(20-len(name))}", nl=False)
|
||||||
|
# Install permissions
|
||||||
|
if plugin.permissions:
|
||||||
|
cur_perm = set(x.name for x in Permission.query.filter(Permission.name.in_(plugin.permissions)).all())
|
||||||
|
all_perm = set(plugin.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
|
||||||
|
plugin.install()
|
||||||
|
click.secho(" ok", fg="green")
|
||||||
|
|
||||||
|
|
||||||
@plugin.command()
|
@plugin.command()
|
||||||
@click.argument("plugin", nargs=-1, type=str)
|
@click.argument("plugin", nargs=-1, type=str)
|
||||||
@click.option("--all", help="Install all enabled plugins", is_flag=True)
|
@click.option("--all", help="Install all enabled plugins", is_flag=True)
|
||||||
|
@ -19,20 +50,7 @@ def plugin():
|
||||||
@pass_context
|
@pass_context
|
||||||
def install(ctx, plugin, all):
|
def install(ctx, plugin, all):
|
||||||
"""Install one or more plugins"""
|
"""Install one or more plugins"""
|
||||||
if not all and len(plugin) == 0:
|
return install_plugin_command(ctx, plugin, all)
|
||||||
ctx.fail("At least one plugin must be specified, or use `--all` flag.")
|
|
||||||
if all:
|
|
||||||
plugins = current_app.config["FG_PLUGINS"].values()
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
plugins = [current_app.config["FG_PLUGINS"][p] for p in plugin]
|
|
||||||
except KeyError as e:
|
|
||||||
ctx.fail(f"Invalid plugin ID, could not find >{e.args[0]}<")
|
|
||||||
for p in plugins:
|
|
||||||
name = p.id.split(".")[-1]
|
|
||||||
click.echo(f"Installing {name}{'.'*(20-len(name))}", nl=False)
|
|
||||||
p.install()
|
|
||||||
click.secho(" ok", fg="green")
|
|
||||||
|
|
||||||
|
|
||||||
@plugin.command()
|
@plugin.command()
|
||||||
|
@ -44,14 +62,16 @@ def uninstall(ctx: click.Context, plugin):
|
||||||
|
|
||||||
if len(plugin) == 0:
|
if len(plugin) == 0:
|
||||||
ctx.fail("At least one plugin must be specified")
|
ctx.fail("At least one plugin must be specified")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
plugins = [current_app.config["FG_PLUGINS"][p] for p in plugin]
|
plugins = {plugin_name: current_app.config["FG_PLUGINS"][plugin_name] for plugin_name in plugin}
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
ctx.fail(f"Invalid plugin ID, could not find >{e.args[0]}<")
|
ctx.fail(f"Invalid plugin ID, could not find >{e.args[0]}<")
|
||||||
|
|
||||||
if (
|
if (
|
||||||
click.prompt(
|
click.prompt(
|
||||||
"You are going to uninstall:\n\n"
|
"You are going to uninstall:\n\n"
|
||||||
f"\t{', '.join([p.id.split('.')[-1] for p in plugins])}\n\n"
|
f"\t{', '.join([plugin_name for plugin_name in plugins.keys()])}\n\n"
|
||||||
"Are you sure?",
|
"Are you sure?",
|
||||||
default="n",
|
default="n",
|
||||||
show_choices=True,
|
show_choices=True,
|
||||||
|
@ -60,10 +80,9 @@ def uninstall(ctx: click.Context, plugin):
|
||||||
!= "y"
|
!= "y"
|
||||||
):
|
):
|
||||||
ctx.exit()
|
ctx.exit()
|
||||||
for p in plugins:
|
for name, plugin in plugins.items():
|
||||||
name = p.id.split(".")[-1]
|
|
||||||
click.echo(f"Uninstalling {name}{'.'*(20-len(name))}", nl=False)
|
click.echo(f"Uninstalling {name}{'.'*(20-len(name))}", nl=False)
|
||||||
p.uninstall()
|
plugin.uninstall()
|
||||||
click.secho(" ok", fg="green")
|
click.secho(" ok", fg="green")
|
||||||
|
|
||||||
|
|
||||||
|
@ -78,7 +97,7 @@ def ls(enabled, no_header):
|
||||||
return p.version
|
return p.version
|
||||||
|
|
||||||
plugins = entry_points(group="flaschengeist.plugins")
|
plugins = entry_points(group="flaschengeist.plugins")
|
||||||
enabled_plugins = [key for key, value in config.items() if "enabled" in value] + [config["FLASCHENGEIST"]["auth"]]
|
enabled_plugins = [key for key, value in config.items() if "enabled" in value and value["enabled"]] + [config["FLASCHENGEIST"]["auth"]]
|
||||||
loaded_plugins = current_app.config["FG_PLUGINS"].keys()
|
loaded_plugins = current_app.config["FG_PLUGINS"].keys()
|
||||||
|
|
||||||
if not no_header:
|
if not no_header:
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -126,7 +126,8 @@ class Plugin:
|
||||||
def install(self):
|
def install(self):
|
||||||
"""Installation routine
|
"""Installation routine
|
||||||
|
|
||||||
Is always called with Flask application context
|
Is always called with Flask application context,
|
||||||
|
it is called after the plugin permissions are installed.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@ from flaschengeist.controller import sessionController, userController
|
||||||
|
|
||||||
|
|
||||||
class AuthRoutePlugin(Plugin):
|
class AuthRoutePlugin(Plugin):
|
||||||
id = "dev.flaschengeist.auth"
|
|
||||||
blueprint = Blueprint("auth", __name__)
|
blueprint = Blueprint("auth", __name__)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -14,12 +14,10 @@ from flaschengeist import logger
|
||||||
|
|
||||||
|
|
||||||
class AuthPlain(AuthPlugin):
|
class AuthPlain(AuthPlugin):
|
||||||
id = "auth_plain"
|
|
||||||
|
|
||||||
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()
|
||||||
|
|
Loading…
Reference in New Issue