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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__all__ = [
 | 
				
			||||||
 | 
					    "plugins_installed",
 | 
				
			||||||
 | 
					    "plugins_loaded",
 | 
				
			||||||
 | 
					    "before_delete_user",
 | 
				
			||||||
 | 
					    "before_role_updated",
 | 
				
			||||||
 | 
					    "before_update_user",
 | 
				
			||||||
 | 
					    "after_role_updated",
 | 
				
			||||||
 | 
					    "Plugin",
 | 
				
			||||||
 | 
					    "AuthPlugin",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Documentation hacks, see https://github.com/mitmproxy/pdoc/issues/320
 | 
				
			||||||
plugins_installed = HookAfter("plugins.installed")
 | 
					plugins_installed = HookAfter("plugins.installed")
 | 
				
			||||||
"""Hook decorator for when all plugins are installed
 | 
					plugins_installed.__doc__ = """Hook decorator for when all plugins are installed
 | 
				
			||||||
    Possible use case would be to populate the database with some presets.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Args:
 | 
					Possible use case would be to populate the database with some presets.
 | 
				
			||||||
        hook_result: void (kwargs)
 | 
					 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Args:
 | 
					Possible use case would be to check if a specific other plugin is loaded and change own behavior
 | 
				
			||||||
        app: Current flask app instance (args)
 | 
					
 | 
				
			||||||
        hook_result: void (kwargs)
 | 
					Passed args:
 | 
				
			||||||
 | 
					    - *app:* Current flask app instance (args)
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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