fix(docs): Various documentation fixed and improvments
This commit is contained in:
parent
a1a20b0d65
commit
c4bf33d1c7
|
@ -44,11 +44,12 @@ 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.
|
||||||
|
|
||||||
$ flaschengeist db upgrade heads
|
$ flaschengeist db upgrade heads
|
||||||
|
|
||||||
## Plugins
|
## Plugins
|
||||||
To only upgrade one plugin:
|
To only upgrade one plugin (for example the `events` plugin):
|
||||||
|
|
||||||
$ flaschengeist db upgrade events@head
|
$ flaschengeist db upgrade events@head
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,9 @@ migrate = Migrate()
|
||||||
|
|
||||||
@migrate.configure
|
@migrate.configure
|
||||||
def configure_alembic(config):
|
def configure_alembic(config):
|
||||||
|
"""Alembic configuration hook
|
||||||
|
|
||||||
|
"""
|
||||||
# Load migration paths from plugins
|
# Load migration paths from plugins
|
||||||
migrations = [str(p.migrations_path) for p in current_app.config["FG_PLUGINS"].values() if p and p.migrations_path]
|
migrations = [str(p.migrations_path) for p in current_app.config["FG_PLUGINS"].values() if p and p.migrations_path]
|
||||||
if len(migrations) > 0:
|
if len(migrations) > 0:
|
||||||
|
|
|
@ -1,3 +1,29 @@
|
||||||
|
"""Flaschengeist Plugins
|
||||||
|
|
||||||
|
## Custom database tables
|
||||||
|
|
||||||
|
You can add tables by declaring them using the SQLAlchemy syntax,
|
||||||
|
then use Alembic to generate migrations for your tables.
|
||||||
|
This allows Flaschengeist to proper up- or downgrade the
|
||||||
|
database tables if an user updates your plugin.
|
||||||
|
|
||||||
|
migrations have to be provided in a directory called `migrations`
|
||||||
|
next to your plugin. E.G.
|
||||||
|
|
||||||
|
myplugin
|
||||||
|
- __init__.py
|
||||||
|
- other/
|
||||||
|
- ...
|
||||||
|
- migrations/
|
||||||
|
|
||||||
|
## Useful Hooks
|
||||||
|
There are some predefined hooks, which might get handy for you.
|
||||||
|
|
||||||
|
For more information, please refer to
|
||||||
|
- `flaschengeist.utils.hook.HookBefore` and
|
||||||
|
- `flaschengeist.utils.hook.HookAfter`
|
||||||
|
"""
|
||||||
|
|
||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
from werkzeug.datastructures import FileStorage
|
from werkzeug.datastructures import FileStorage
|
||||||
|
@ -10,48 +36,81 @@ from flaschengeist.models.user import _Avatar, User
|
||||||
from flaschengeist.models.setting import _PluginSetting
|
from flaschengeist.models.setting import _PluginSetting
|
||||||
from flaschengeist.utils.hook import HookBefore, HookAfter
|
from flaschengeist.utils.hook import HookBefore, HookAfter
|
||||||
|
|
||||||
plugins_installed = HookAfter("plugins.installed")
|
__all__ = [
|
||||||
"""Hook decorator for when all plugins are installed
|
"plugins_installed",
|
||||||
Possible use case would be to populate the database with some presets.
|
"plugins_loaded",
|
||||||
|
"before_delete_user",
|
||||||
|
"before_role_updated",
|
||||||
|
"before_update_user",
|
||||||
|
"after_role_updated",
|
||||||
|
"Plugin",
|
||||||
|
"AuthPlugin",
|
||||||
|
]
|
||||||
|
|
||||||
Args:
|
# Documentation hacks, see https://github.com/mitmproxy/pdoc/issues/320
|
||||||
hook_result: void (kwargs)
|
plugins_installed = HookAfter("plugins.installed")
|
||||||
|
plugins_installed.__doc__ = """Hook decorator for when all plugins are installed
|
||||||
|
|
||||||
|
Possible use case would be to populate the database with some presets.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
plugins_loaded = HookAfter("plugins.loaded")
|
plugins_loaded = HookAfter("plugins.loaded")
|
||||||
"""Hook decorator for when all plugins are loaded
|
plugins_loaded.__doc__ = """Hook decorator for when all plugins are loaded
|
||||||
|
|
||||||
Possible use case would be to check if a specific other plugin is loaded and change own behavior
|
Possible use case would be to check if a specific other plugin is loaded and change own behavior
|
||||||
|
|
||||||
Args:
|
Passed args:
|
||||||
app: Current flask app instance (args)
|
- *app:* Current flask app instance (args)
|
||||||
hook_result: void (kwargs)
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
before_role_updated = HookBefore("update_role")
|
before_role_updated = HookBefore("update_role")
|
||||||
"""Hook decorator for when roles are modified
|
before_role_updated.__doc__ = """Hook decorator for when roles are modified
|
||||||
Args:
|
|
||||||
role: Role object to modify
|
Passed args:
|
||||||
new_name: New name if the name was changed (None if delete)
|
- *role:* `flaschengeist.models.user.Role` to modify
|
||||||
|
- *new_name:* New name if the name was changed (*None* if delete)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
after_role_updated = HookAfter("update_role")
|
after_role_updated = HookAfter("update_role")
|
||||||
"""Hook decorator for when roles are modified
|
after_role_updated.__doc__ = """Hook decorator for when roles are modified
|
||||||
Args:
|
|
||||||
role: Role object containing the modified role
|
Passed args:
|
||||||
new_name: New name if the name was changed (None if deleted)
|
- *role:* modified `flaschengeist.models.user.Role`
|
||||||
|
- *new_name:* New name if the name was changed (*None* if deleted)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
before_update_user = HookBefore("update_user")
|
before_update_user = HookBefore("update_user")
|
||||||
"""Hook decorator, when ever an user update is done, this is called before.
|
before_update_user.__doc__ = """Hook decorator, when ever an user update is done, this is called before.
|
||||||
Args:
|
|
||||||
user: User object
|
Passed args:
|
||||||
|
- *user:* `flaschengeist.models.user.User` object
|
||||||
"""
|
"""
|
||||||
|
|
||||||
before_delete_user = HookBefore("delete_user")
|
before_delete_user = HookBefore("delete_user")
|
||||||
"""Hook decorator,this is called before an user gets deleted.
|
before_delete_user.__doc__ = """Hook decorator,this is called before an user gets deleted.
|
||||||
Args:
|
|
||||||
user: User object
|
Passed args:
|
||||||
|
- *user:* `flaschengeist.models.user.User` object
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class Plugin:
|
class Plugin:
|
||||||
"""Base class for all Plugins
|
"""Base class for all Plugins
|
||||||
If your class uses custom models add a static property called ``models``"""
|
|
||||||
|
All plugins must be derived from this class.
|
||||||
|
There are some static properties a plugin must provide,
|
||||||
|
and some properties a plugin can provide if you might want
|
||||||
|
to use more functionality.
|
||||||
|
|
||||||
|
Required:
|
||||||
|
- *id*: Unique identifier of your plugin
|
||||||
|
|
||||||
|
Optional:
|
||||||
|
- *blueprint*: `flask.Blueprint` providing your routes
|
||||||
|
- *permissions*: List of your custom permissions
|
||||||
|
- *models*: Your models, used for API export
|
||||||
|
- *version*: Version of your plugin, can also be guessed by Flaschengeist
|
||||||
|
"""
|
||||||
|
|
||||||
blueprint = None # You have to override
|
blueprint = None # You have to override
|
||||||
"""Override with a `flask.blueprint` if the plugin uses custom routes"""
|
"""Override with a `flask.blueprint` if the plugin uses custom routes"""
|
||||||
|
@ -61,14 +120,18 @@ class Plugin:
|
||||||
A good style is to name the permissions with a prefix related to the plugin name,
|
A good style is to name the permissions with a prefix related to the plugin name,
|
||||||
to prevent clashes with other plugins. E. g. instead of *delete* use *plugin_delete*.
|
to prevent clashes with other plugins. E. g. instead of *delete* use *plugin_delete*.
|
||||||
"""
|
"""
|
||||||
id = "dev.flaschengeist.plugin" # You have to override
|
|
||||||
"""Override with the unique ID of the plugin (Hint: FQN)"""
|
models = None
|
||||||
name = "plugin" # You have to override
|
"""Override with models module
|
||||||
"""Override with human readable name of the plugin"""
|
|
||||||
models = None # You have to override
|
Used for API export, has to be a static property
|
||||||
"""Override with models module"""
|
"""
|
||||||
migrations_path = None # Override this with the location of your db migrations directory
|
|
||||||
"""Override with path to migration files, if custome db tables are used"""
|
version = None
|
||||||
|
"""Override with a custom version, optional
|
||||||
|
|
||||||
|
If not set, the version is guessed from the package / distribution
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, config=None):
|
def __init__(self, config=None):
|
||||||
"""Constructor called by create_app
|
"""Constructor called by create_app
|
||||||
|
@ -233,14 +296,14 @@ class AuthPlugin(Plugin):
|
||||||
"""
|
"""
|
||||||
raise NotFound
|
raise NotFound
|
||||||
|
|
||||||
def set_avatar(self, user: User, file: FileStorage):
|
def set_avatar(self, user, file):
|
||||||
"""Set the avatar for given user (if supported by auth backend)
|
"""Set the avatar for given user (if supported by auth backend)
|
||||||
|
|
||||||
Default behavior is to use native Image objects stored on the Flaschengeist server
|
Default behavior is to use native Image objects stored on the Flaschengeist server
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
user: User to set the avatar for
|
user: User to set the avatar for
|
||||||
file: FileStorage object uploaded by the user
|
file: `werkzeug.datastructures.FileStorage` uploaded by the user
|
||||||
Raises:
|
Raises:
|
||||||
MethodNotAllowed: If not supported by Backend
|
MethodNotAllowed: If not supported by Backend
|
||||||
Any valid HTTP exception
|
Any valid HTTP exception
|
||||||
|
|
|
@ -131,7 +131,7 @@ def get_balance(userid, current_session: Session):
|
||||||
|
|
||||||
Route: ``/users/<userid>/balance`` | Method: ``GET``
|
Route: ``/users/<userid>/balance`` | Method: ``GET``
|
||||||
|
|
||||||
GET-parameters: ```{from?: string, to?: string}```
|
GET-parameters: ``{from?: string, to?: string}``
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
userid: Userid of user to get balance from
|
userid: Userid of user to get balance from
|
||||||
|
@ -170,7 +170,7 @@ def get_transactions(userid, current_session: Session):
|
||||||
|
|
||||||
Route: ``/users/<userid>/balance/transactions`` | Method: ``GET``
|
Route: ``/users/<userid>/balance/transactions`` | Method: ``GET``
|
||||||
|
|
||||||
GET-parameters: ```{from?: string, to?: string, limit?: int, offset?: int}```
|
GET-parameters: ``{from?: string, to?: string, limit?: int, offset?: int}``
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
userid: Userid of user to get transactions from
|
userid: Userid of user to get transactions from
|
||||||
|
|
|
@ -7,6 +7,7 @@ _hooks_after = {}
|
||||||
|
|
||||||
def Hook(function=None, id=None):
|
def Hook(function=None, id=None):
|
||||||
"""Hook decorator
|
"""Hook decorator
|
||||||
|
|
||||||
Use to decorate functions as hooks, so plugins can hook up their custom functions.
|
Use to decorate functions as hooks, so plugins can hook up their custom functions.
|
||||||
"""
|
"""
|
||||||
# `id` passed as `arg` not `kwarg`
|
# `id` passed as `arg` not `kwarg`
|
||||||
|
@ -38,8 +39,10 @@ def Hook(function=None, id=None):
|
||||||
|
|
||||||
def HookBefore(id: str):
|
def HookBefore(id: str):
|
||||||
"""Decorator for functions to be called before a Hook-Function is called
|
"""Decorator for functions to be called before a Hook-Function is called
|
||||||
|
|
||||||
The hooked up function must accept the same arguments as the function hooked onto,
|
The hooked up function must accept the same arguments as the function hooked onto,
|
||||||
as the functions are called with the same arguments.
|
as the functions are called with the same arguments.
|
||||||
|
|
||||||
Hint: This enables you to modify the arguments!
|
Hint: This enables you to modify the arguments!
|
||||||
"""
|
"""
|
||||||
if not id or not isinstance(id, str):
|
if not id or not isinstance(id, str):
|
||||||
|
@ -54,9 +57,18 @@ def HookBefore(id: str):
|
||||||
|
|
||||||
def HookAfter(id: str):
|
def HookAfter(id: str):
|
||||||
"""Decorator for functions to be called after a Hook-Function is called
|
"""Decorator for functions to be called after a Hook-Function is called
|
||||||
|
|
||||||
As with the HookBefore, the hooked up function must accept the same
|
As with the HookBefore, the hooked up function must accept the same
|
||||||
arguments as the function hooked onto, but also receives a
|
arguments as the function hooked onto, but also receives a
|
||||||
`hook_result` kwarg containing the result of the function.
|
`hook_result` kwarg containing the result of the function.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```py
|
||||||
|
@HookAfter("some.id")
|
||||||
|
def my_func(hook_result):
|
||||||
|
# This function is executed after the function registered with "some.id"
|
||||||
|
print(hook_result) # This is the result of the function
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not id or not isinstance(id, str):
|
if not id or not isinstance(id, str):
|
||||||
|
|
Loading…
Reference in New Issue