Entwickler-Dokumentation

Leitfaden zur Entwicklung von CloudService Plugins.

CloudService - Entwickelt von Andreas Borowczak | Aboro IT

Übersicht

CloudService verwendet ein modulares Plugin-System basierend auf Django Apps. Plugins können:

  • Dashboard-Widgets hinzufügen
  • Datei-Vorschauen bereitstellen
  • Eigene Einstellungen haben
  • Hooks für verschiedene Events registrieren
Installation

Plugins können auf zwei Arten installiert werden:

  1. Lokaler Ordner: Plugin in plugins/installed/ ablegen
  2. ZIP-Upload: Plugin als ZIP über die Einstellungen hochladen

Plugin-Struktur

Ein Plugin besteht aus folgenden Dateien:

mein_plugin/
├── __init__.py          # Python-Paket (erforderlich)
├── plugin.json          # Manifest mit Metadaten (erforderlich)
├── apps.py              # Django AppConfig (erforderlich)
├── widget.py            # Widget-Provider (optional)
├── handlers.py          # Hook-Handler (optional)
└── templates/           # Template-Ordner (optional)
    └── mein_plugin/
        └── widget.html
Minimale Dateien
  • __init__.py - Kann leer sein oder default_app_config enthalten
  • plugin.json - Manifest mit Name, Version, etc.
  • apps.py - Django AppConfig mit ready() Methode

plugin.json Manifest

Die plugin.json definiert alle Plugin-Metadaten:

{
  "name": "Mein Plugin",
  "slug": "mein-plugin",
  "version": "1.0.0",
  "author": "Ihr Name",
  "description": "Beschreibung des Plugins",

  "django_app": {
    "app_config": "mein_plugin.apps.MeinPluginConfig"
  },

  "requirements": {
    "django": ">=5.0,<6.0",
    "python": ">=3.10"
  },

  "hooks": {
    "ui_dashboard_widget": {
      "handler": "mein_plugin.widget.MeinWidgetProvider",
      "priority": 10
    }
  },

  "settings": {
    "has_settings": true,
    "schema": {
      "api_key": {
        "type": "password",
        "label": "API Key",
        "required": true
      },
      "option": {
        "type": "select",
        "label": "Option",
        "options": [
          {"value": "a", "label": "Option A"},
          {"value": "b", "label": "Option B"}
        ]
      }
    }
  }
}
Pflichtfelder
FeldBeschreibung
nameAnzeigename des Plugins
slugURL-freundliche ID (a-z, 0-9, -)
versionSemver-Version (1.0.0)
django_app.app_configPfad zur AppConfig-Klasse

Dashboard Widgets

Widgets werden auf der Landing Page angezeigt. Erstellen Sie eine Widget-Klasse:

# widget.py
from plugins.widgets import DashboardWidgetProvider

class MeinWidgetProvider(DashboardWidgetProvider):
    widget_id = "mein_widget"
    widget_name = "Mein Widget"
    widget_icon = "bi-star"        # Bootstrap Icon
    widget_size = "medium"         # small, medium, large
    widget_order = 50              # Sortierung (niedriger = weiter oben)

    def get_context(self, request):
        """Daten für das Template."""
        return {
            'message': 'Hallo Welt!',
            'user': request.user.username,
        }

    def get_template_name(self):
        """Pfad zum Template."""
        return 'mein_plugin/widget.html'

    def is_visible(self, request):
        """Optional: Widget nur für bestimmte User zeigen."""
        return request.user.is_authenticated
Widget-Größen
GrößeBootstrap-KlasseBreite
smallcol-md-41/3
mediumcol-md-61/2
largecol-md-12Volle Breite

Plugin-Einstellungen

Plugins können konfigurierbare Einstellungen haben:

Schema in plugin.json
"settings": {
  "has_settings": true,
  "schema": {
    "feldname": {
      "type": "text|password|number|boolean|select|textarea",
      "label": "Anzeigename",
      "help": "Hilfetext",
      "required": true|false,
      "default": "Standardwert",
      "placeholder": "Platzhalter",
      "options": [...]  // Nur für select
    }
  }
}
Einstellungen im Code lesen
from plugins.models import Plugin

# In Ihrem Widget oder Handler:
plugin = Plugin.objects.get(slug='mein-plugin')
api_key = plugin.settings.get('api_key', '')
option = plugin.settings.get('option', 'default')
Verfügbare Feldtypen
TypHTML-ElementBeschreibung
textinput[text]Einzeiliger Text
passwordinput[password]Passwort/API-Key
numberinput[number]Dezimalzahl
integerinput[number]Ganzzahl
booleancheckboxJa/Nein
selectselectDropdown
textareatextareaMehrzeiliger Text

Hook-System

Hooks erlauben es, auf Events zu reagieren oder Funktionalität zu erweitern:

Hook registrieren (in apps.py)
from django.apps import AppConfig

class MeinPluginConfig(AppConfig):
    name = 'mein_plugin'

    def ready(self):
        from plugins.hooks import hook_registry, UI_DASHBOARD_WIDGET
        from mein_plugin.widget import MeinWidgetProvider

        hook_registry.register(
            UI_DASHBOARD_WIDGET,
            MeinWidgetProvider,
            priority=10
        )
Verfügbare Hooks
HookBeschreibung
UI_DASHBOARD_WIDGETDashboard-Widget hinzufügen
FILE_PREVIEW_PROVIDERDateivorschau-Handler
UI_FILE_ACTION_BUTTONAktions-Button bei Dateien
UI_MENU_ITEMMenüeintrag hinzufügen
STORAGE_FILE_UPLOADEDEvent: Datei hochgeladen
STORAGE_FILE_DELETEDEvent: Datei gelöscht

Templates

Plugin-Templates werden automatisch gefunden wenn sie im richtigen Ordner liegen:

mein_plugin/
└── templates/
    └── mein_plugin/
        └── widget.html
Widget-Template Beispiel
<div class="mein-widget">
    <h4></h4>
    <p>Benutzer: </p>

    <style>
        .mein-widget { padding: 10px; }
    </style>
</div>
Verfügbare Variablen
  • widget_context - Dict von get_context()
  • request - HTTP Request
  • user - Aktueller Benutzer

Komplettes Beispiel-Plugin

Hier ein vollständiges Beispiel für ein "Zitat des Tages" Widget:

__init__.py
"""Quote of the Day Plugin"""
default_app_config = 'quote_plugin.apps.QuoteConfig'
plugin.json
{
  "name": "Zitat des Tages",
  "slug": "quote-plugin",
  "version": "1.0.0",
  "author": "Entwickler",
  "description": "Zeigt ein inspirierendes Zitat an.",
  "django_app": {
    "app_config": "quote_plugin.apps.QuoteConfig"
  }
}
apps.py
from django.apps import AppConfig

class QuoteConfig(AppConfig):
    name = 'quote_plugin'

    def ready(self):
        from plugins.hooks import hook_registry, UI_DASHBOARD_WIDGET
        from quote_plugin.widget import QuoteWidgetProvider

        hook_registry.register(
            UI_DASHBOARD_WIDGET,
            QuoteWidgetProvider,
            priority=30
        )
widget.py
import random
from plugins.widgets import DashboardWidgetProvider

class QuoteWidgetProvider(DashboardWidgetProvider):
    widget_id = "quote_widget"
    widget_name = "Zitat des Tages"
    widget_icon = "bi-quote"
    widget_size = "medium"
    widget_order = 30

    QUOTES = [
        ("Der Weg ist das Ziel.", "Konfuzius"),
        ("Wissen ist Macht.", "Francis Bacon"),
        ("Carpe Diem.", "Horaz"),
    ]

    def get_context(self, request):
        quote, author = random.choice(self.QUOTES)
        return {'quote': quote, 'author': author}

    def get_template_name(self):
        return 'quote_plugin/widget.html'
templates/quote_plugin/widget.html
<div class="text-center py-3">
    <i class="bi bi-quote display-4 text-primary"></i>
    <blockquote class="blockquote mt-3">
        <p></p>
        <footer class="blockquote-footer">
            
        </footer>
    </blockquote>
</div>

Plugin als ZIP verteilen

Um ein Plugin als ZIP zu verteilen:

  1. Erstellen Sie die Plugin-Ordnerstruktur
  2. Packen Sie den Ordner als ZIP:
    # Linux/Mac
    zip -r mein_plugin.zip mein_plugin/
    
    # Windows PowerShell
    Compress-Archive -Path mein_plugin -DestinationPath mein_plugin.zip
  3. Die ZIP-Struktur sollte so aussehen:
    mein_plugin.zip
    └── mein_plugin/
        ├── __init__.py
        ├── plugin.json
        ├── apps.py
        └── ...