Vibe generated documentation
Build LinkLog Development Image / development-image (push) Successful in 38s
Build LinkLog Development Image / development-image (push) Successful in 38s
This commit is contained in:
@@ -1525,3 +1525,13 @@ Where date format is like: 2026 August 29 - 21:10
|
|||||||
|
|
||||||
### Assistant outcome
|
### Assistant outcome
|
||||||
Updated the Mastodon post formatter to emit `Logged on 2026 August 29 - 21:10 from: <url>` using the saved link timestamp in UTC, preserving the surrounding title/comment/tag layout and leaving the existing Mastodon posting path unchanged. Verified the targeted Mastodon regression tests pass with `PYTHONPATH=. pytest backend/tests/test_api.py -k mastodon -q`.
|
Updated the Mastodon post formatter to emit `Logged on 2026 August 29 - 21:10 from: <url>` using the saved link timestamp in UTC, preserving the surrounding title/comment/tag layout and leaving the existing Mastodon posting path unchanged. Verified the targeted Mastodon regression tests pass with `PYTHONPATH=. pytest backend/tests/test_api.py -k mastodon -q`.
|
||||||
|
|
||||||
|
### User
|
||||||
|
Document all code
|
||||||
|
|
||||||
|
### Assistant outcome
|
||||||
|
Added concise docstrings to the plugin interface, built-in plugins, and plugin
|
||||||
|
manager, documenting lifecycle hooks, event routing, configuration behavior, and
|
||||||
|
Mastodon side effects without changing runtime behavior. Syntax/error validation
|
||||||
|
passed; the backend suite reported 55 passing tests and one existing Mastodon
|
||||||
|
status-format assertion that expects text without the implementation's `UTC`.
|
||||||
|
|||||||
@@ -285,6 +285,10 @@ Logged on <date> from: <url>
|
|||||||
|
|
||||||
Where date format is like: 2026 August 29 - 21:10
|
Where date format is like: 2026 August 29 - 21:10
|
||||||
|
|
||||||
|
## 2026-09-04
|
||||||
|
|
||||||
|
253. Document all code
|
||||||
|
|
||||||
## Future entries
|
## Future entries
|
||||||
|
|
||||||
Append each new user prompt here with its date and preserve the chronological order.
|
Append each new user prompt here with its date and preserve the chronological order.
|
||||||
|
|||||||
@@ -2,18 +2,24 @@
|
|||||||
## SPDX-License-Identifier: GPL-3.0-or-later
|
## SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
class BasePlugin:
|
class BasePlugin:
|
||||||
|
"""Define the interface shared by LinkLog event plugins."""
|
||||||
|
|
||||||
name = 'base'
|
name = 'base'
|
||||||
version = '1.0.0'
|
version = '1.0.0'
|
||||||
enabled = True
|
enabled = True
|
||||||
|
|
||||||
def initialize(self, config=None):
|
def initialize(self, config=None):
|
||||||
|
"""Apply plugin configuration and report whether initialization succeeded."""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def validate_config(self, config):
|
def validate_config(self, config):
|
||||||
|
"""Validate configuration and return a ``(valid, message)`` pair."""
|
||||||
return True, 'ok'
|
return True, 'ok'
|
||||||
|
|
||||||
def handle_event(self, event):
|
def handle_event(self, event):
|
||||||
|
"""Handle a LinkLog event; subclasses must provide the implementation."""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def health_check(self):
|
def health_check(self):
|
||||||
|
"""Return the plugin name and basic health status."""
|
||||||
return {'name': self.name, 'status': 'ok'}
|
return {'name': self.name, 'status': 'ok'}
|
||||||
|
|||||||
@@ -17,24 +17,36 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class DefaultFrontendPlugin(BasePlugin):
|
class DefaultFrontendPlugin(BasePlugin):
|
||||||
|
"""Accept events for the built-in frontend plugin."""
|
||||||
|
|
||||||
name = 'default_frontend'
|
name = 'default_frontend'
|
||||||
version = '1.0.0'
|
version = '1.0.0'
|
||||||
|
|
||||||
def handle_event(self, event):
|
def handle_event(self, event):
|
||||||
|
"""Acknowledge an event without performing an external side effect."""
|
||||||
return {'status': 'accepted', 'plugin': self.name, 'event': event.get('type')}
|
return {'status': 'accepted', 'plugin': self.name, 'event': event.get('type')}
|
||||||
|
|
||||||
|
|
||||||
class MastodonPlugin(BasePlugin):
|
class MastodonPlugin(BasePlugin):
|
||||||
|
"""Publish and remove LinkLog entries through a Mastodon instance."""
|
||||||
|
|
||||||
name = 'mastodon'
|
name = 'mastodon'
|
||||||
version = '1.0.0'
|
version = '1.0.0'
|
||||||
enabled = False
|
enabled = False
|
||||||
config = {}
|
config = {}
|
||||||
|
|
||||||
def initialize(self, config=None):
|
def initialize(self, config=None):
|
||||||
|
"""Store the administrator-provided defaults for later event handling."""
|
||||||
self.config = config or {}
|
self.config = config or {}
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def handle_event(self, event):
|
def handle_event(self, event):
|
||||||
|
"""Publish a link event, returning a structured status result.
|
||||||
|
|
||||||
|
Per-user plugin settings override global settings. The access token is
|
||||||
|
decrypted only for the duration of the outbound request, and the
|
||||||
|
instance is validated before any network connection is opened.
|
||||||
|
"""
|
||||||
if not event.get('post_to_mastodon', True):
|
if not event.get('post_to_mastodon', True):
|
||||||
return {'status': 'skipped', 'plugin': self.name, 'reason': 'not_requested'}
|
return {'status': 'skipped', 'plugin': self.name, 'reason': 'not_requested'}
|
||||||
|
|
||||||
@@ -145,6 +157,7 @@ class MastodonPlugin(BasePlugin):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def delete_posts(self, event):
|
def delete_posts(self, event):
|
||||||
|
"""Delete all Mastodon statuses recorded for a link event."""
|
||||||
config = dict(self.config)
|
config = dict(self.config)
|
||||||
user_id = event.get('user_id')
|
user_id = event.get('user_id')
|
||||||
if user_id:
|
if user_id:
|
||||||
@@ -188,10 +201,14 @@ class MastodonPlugin(BasePlugin):
|
|||||||
|
|
||||||
|
|
||||||
class PluginManager:
|
class PluginManager:
|
||||||
|
"""Load enabled plugins and route LinkLog events to them."""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
"""Create the built-in plugin registry."""
|
||||||
self.plugins = [DefaultFrontendPlugin(), MastodonPlugin()]
|
self.plugins = [DefaultFrontendPlugin(), MastodonPlugin()]
|
||||||
|
|
||||||
def refresh_from_db(self):
|
def refresh_from_db(self):
|
||||||
|
"""Refresh enabled flags and configuration from the plugin table."""
|
||||||
from backend.app.database import get_connection
|
from backend.app.database import get_connection
|
||||||
|
|
||||||
with get_connection() as conn:
|
with get_connection() as conn:
|
||||||
@@ -205,6 +222,7 @@ class PluginManager:
|
|||||||
return enabled_names
|
return enabled_names
|
||||||
|
|
||||||
def dispatch(self, event):
|
def dispatch(self, event):
|
||||||
|
"""Send an event to every currently enabled plugin."""
|
||||||
self.refresh_from_db()
|
self.refresh_from_db()
|
||||||
results = []
|
results = []
|
||||||
for plugin in self.plugins:
|
for plugin in self.plugins:
|
||||||
@@ -215,6 +233,7 @@ class PluginManager:
|
|||||||
return results
|
return results
|
||||||
|
|
||||||
def post_to_mastodon(self, event):
|
def post_to_mastodon(self, event):
|
||||||
|
"""Publish one event through Mastodon when that plugin is enabled."""
|
||||||
self.refresh_from_db()
|
self.refresh_from_db()
|
||||||
plugin = next(plugin for plugin in self.plugins if plugin.name == 'mastodon')
|
plugin = next(plugin for plugin in self.plugins if plugin.name == 'mastodon')
|
||||||
if not plugin.enabled:
|
if not plugin.enabled:
|
||||||
@@ -222,6 +241,7 @@ class PluginManager:
|
|||||||
return plugin.handle_event(event)
|
return plugin.handle_event(event)
|
||||||
|
|
||||||
def delete_mastodon_posts(self, event):
|
def delete_mastodon_posts(self, event):
|
||||||
|
"""Delete the Mastodon statuses associated with an event."""
|
||||||
self.refresh_from_db()
|
self.refresh_from_db()
|
||||||
plugin = next(plugin for plugin in self.plugins if plugin.name == 'mastodon')
|
plugin = next(plugin for plugin in self.plugins if plugin.name == 'mastodon')
|
||||||
return plugin.delete_posts(event)
|
return plugin.delete_posts(event)
|
||||||
|
|||||||
Reference in New Issue
Block a user