diff --git a/core/dashboard/routes.py b/core/dashboard/routes.py index 7e1ccbc..f279325 100644 --- a/core/dashboard/routes.py +++ b/core/dashboard/routes.py @@ -918,12 +918,15 @@ async def get_project_detail(project_id: str) -> dict | None: # Get recent activity for this project audit_logger = get_audit_logger() - recent_entries = audit_logger.get_recent_entries(limit=20) + recent_entries = audit_logger.get_recent_entries(limit=60) project_activity = [ e for e in recent_entries - if e.get("metadata", {}).get("project_id") == project_id - or e.get("metadata", {}).get("site") == site_id + if ( + e.get("metadata", {}).get("project_id") == project_id + or e.get("metadata", {}).get("site") == site_id + ) + and e.get("event_type", "") not in ("health_metric_recorded", "health_check") ][:5] # Get cached health status diff --git a/core/health.py b/core/health.py index ebc206e..78d8c22 100644 --- a/core/health.py +++ b/core/health.py @@ -563,13 +563,26 @@ class HealthMonitor: try: import aiohttp - auth = aiohttp.BasicAuth( - config.username or "", - config.app_password or "", - ) + if plugin_type == "woocommerce": + # WooCommerce uses consumer_key/consumer_secret + ck = getattr(config, "consumer_key", None) or "" + cs = getattr(config, "consumer_secret", None) or "" + # consumer_key/consumer_secret may be in model_extra + if not ck and hasattr(config, "model_extra"): + ck = (config.model_extra or {}).get("consumer_key", "") + cs = (config.model_extra or {}).get("consumer_secret", "") + auth = aiohttp.BasicAuth(ck, cs) + auth_check_url = f"{config.url}/wp-json/wc/v3/system_status" + else: + auth = aiohttp.BasicAuth( + config.username or "", + config.app_password or "", + ) + auth_check_url = f"{config.url}/wp-json/wp/v2/users/me" + async with aiohttp.ClientSession(auth=auth) as session: async with session.get( - f"{config.url}/wp-json/wp/v2/users/me", + auth_check_url, timeout=aiohttp.ClientTimeout(total=10), ssl=False, ) as resp: diff --git a/core/templates/dashboard/connect.html b/core/templates/dashboard/connect.html index 96d8306..57bbf9b 100644 --- a/core/templates/dashboard/connect.html +++ b/core/templates/dashboard/connect.html @@ -28,14 +28,35 @@ {% endif %} - -
{{ t.your_api_key }}
-
-
+
+
{% if api_keys %}
@@ -132,8 +153,8 @@ async function createKey() {
if (resp.ok && data.key) {
document.getElementById('new-key-value').textContent = data.key.key;
document.getElementById('new-key-display').classList.remove('hidden');
- // Reload to show in table
- setTimeout(() => location.reload(), 500);
+ document.getElementById('new-key-display').classList.add('flex');
+ // Modal stays open — user clicks "Done" to dismiss
} else {
alert(data.error || 'Failed to create key');
}
@@ -180,6 +201,12 @@ function copyNewKey() {
navigator.clipboard.writeText(key);
}
+function closeNewKeyModal() {
+ document.getElementById('new-key-display').classList.add('hidden');
+ document.getElementById('new-key-display').classList.remove('flex');
+ location.reload();
+}
+
function copyConfig() {
const text = document.getElementById('config-output').textContent;
navigator.clipboard.writeText(text);
diff --git a/plugins/woocommerce/plugin.py b/plugins/woocommerce/plugin.py
index 481ddee..b7e6dbc 100644
--- a/plugins/woocommerce/plugin.py
+++ b/plugins/woocommerce/plugin.py
@@ -47,7 +47,7 @@ class WooCommercePlugin(BasePlugin):
@staticmethod
def get_required_config_keys() -> list[str]:
"""Return required configuration keys"""
- return ["url", "username", "app_password"]
+ return ["url"]
def __init__(self, config: dict[str, Any], project_id: str | None = None):
"""
@@ -55,16 +55,30 @@ class WooCommercePlugin(BasePlugin):
Args:
config: Configuration dictionary containing:
- - url: WordPress site URL
- - username: WordPress username
- - app_password: WordPress application password
+ - url: WordPress/WooCommerce site URL
+ - consumer_key/consumer_secret: WooCommerce REST API keys (preferred)
+ - username/app_password: WordPress application password (fallback)
project_id: Optional project ID (auto-generated if not provided)
"""
super().__init__(config, project_id=project_id)
- # Create WordPress API client (WooCommerce uses WordPress REST API)
+ # WooCommerce supports two credential formats:
+ # 1. consumer_key/consumer_secret (WooCommerce REST API keys — preferred)
+ # 2. username/app_password (WordPress Application Passwords — legacy fallback)
+ username = config.get("consumer_key") or config.get("username")
+ password = config.get("consumer_secret") or config.get("app_password")
+
+ if not username or not password:
+ from plugins.wordpress.client import ConfigurationError
+
+ raise ConfigurationError(
+ "WooCommerce credentials not configured. "
+ "Please set either CONSUMER_KEY/CONSUMER_SECRET or USERNAME/APP_PASSWORD."
+ )
+
+ # Create WordPress API client
self.client = WordPressClient(
- site_url=config["url"], username=config["username"], app_password=config["app_password"]
+ site_url=config["url"], username=username, app_password=password
)
# Initialize WooCommerce handlers
diff --git a/tests/test_woocommerce_plugin.py b/tests/test_woocommerce_plugin.py
index 1c2b7d6..b051717 100644
--- a/tests/test_woocommerce_plugin.py
+++ b/tests/test_woocommerce_plugin.py
@@ -44,11 +44,10 @@ class TestWooCommercePluginInit:
assert WooCommercePlugin.get_plugin_name() == "woocommerce"
def test_required_config_keys(self):
- """Should require url, username, app_password."""
+ """Should require url only (credentials checked at init)."""
keys = WooCommercePlugin.get_required_config_keys()
assert "url" in keys
- assert "username" in keys
- assert "app_password" in keys
+ assert len(keys) == 1
def test_missing_url_raises(self):
"""Should raise ValueError for missing URL."""
@@ -57,9 +56,11 @@ class TestWooCommercePluginInit:
WooCommercePlugin(config)
def test_missing_credentials_raises(self):
- """Should raise ValueError for missing credentials."""
+ """Should raise ConfigurationError for missing credentials."""
+ from plugins.wordpress.client import ConfigurationError
+
config = {"url": "https://shop.example.com"}
- with pytest.raises(ValueError, match="Missing required configuration"):
+ with pytest.raises(ConfigurationError, match="credentials not configured"):
WooCommercePlugin(config)
def test_custom_project_id(self):