diff --git a/WhatsupDocker/WhatsupDocker.php b/WhatsupDocker/WhatsupDocker.php new file mode 100644 index 0000000000..30b8d681d4 --- /dev/null +++ b/WhatsupDocker/WhatsupDocker.php @@ -0,0 +1,148 @@ +jar = new \GuzzleHttp\Cookie\CookieJar; // Uncomment if cookies need to be set + } + + public function test() + { + // If auth credentials are provided, test the authenticated endpoint + if ($this->hasAuthCredentials()) { + // Test containers endpoint which requires authentication + $test = parent::appTest($this->url('api/containers'), $this->getAttrs()); + echo $test->status; + } else { + // No auth configured, test the public app endpoint + $test = parent::appTest($this->url('api/app'), $this->getAttrs()); + echo $test->status; + } + } + + public function livestats() + { + $status = 'inactive'; + + try { + // Get watched containers from WUD API + $res = parent::execute($this->url('api/containers'), $this->getAttrs()); + $containers = json_decode($res->getBody(), true); + + if ($containers && is_array($containers)) { + $status = 'active'; + + // Calculate container statistics + $totalContainers = count($containers); + $updatableContainers = 0; + $watchedContainers = 0; + + foreach ($containers as $container) { + // Count updatable containers (based on API doc structure) + if (isset($container['updateAvailable']) && $container['updateAvailable'] === true) { + $updatableContainers++; + } + + // All containers returned by /api/containers are watched containers + $watchedContainers++; + } + + $details = ['visiblestats' => []]; + + // Show configured stats, or all if none selected + $availableStats = isset($this->config->availablestats) && !empty($this->config->availablestats) + ? $this->config->availablestats + : array_keys(self::getAvailableStats()); + + foreach ($availableStats as $stat) { + $newstat = new \stdClass(); + $newstat->title = self::getAvailableStats()[$stat]; + + switch ($stat) { + case 'TotalContainers': + $newstat->value = $totalContainers; + break; + case 'UpdatableContainers': + $newstat->value = $updatableContainers; + break; + case 'WatchedContainers': + $newstat->value = $watchedContainers; + break; + default: + $newstat->value = 0; + } + + $details['visiblestats'][] = $newstat; + } + + return parent::getLiveStats($status, $details); + } + } catch (Exception $e) { + // If auth is configured but containers API fails, don't fallback + if ($this->hasAuthCredentials()) { + $status = 'inactive'; + } else { + // No auth configured, try basic status check with app endpoint + try { + $res = parent::execute($this->url('api/app'), $this->getAttrs()); + if ($res->getStatusCode() === 200) { + $status = 'active'; + } + } catch (Exception $e2) { + $status = 'inactive'; + } + } + } + + return parent::getLiveStats($status, []); + } + + private function hasAuthCredentials() + { + return !empty($this->config->username) && !empty($this->config->password); + } + + private function getAttrs() + { + $attrs = [ + 'headers' => [ + 'Accept' => 'application/json', + 'Content-Type' => 'application/json', + ] + ]; + + // Add basic authentication if both username and password are configured + if ($this->hasAuthCredentials()) { + $attrs['auth'] = [$this->config->username, $this->config->password]; + } + + return $attrs; + } + + public function url($endpoint) + { + $base_url = parent::normaliseurl($this->config->url); + // Ensure trailing slash for WUD API + if (!str_ends_with($base_url, '/')) { + $base_url .= '/'; + } + return $base_url . $endpoint; + } + + public static function getAvailableStats() + { + return [ + 'TotalContainers' => 'Total', + 'UpdatableContainers' => 'Updatable', + 'WatchedContainers' => 'Watched', + ]; + } +} diff --git a/WhatsupDocker/app.json b/WhatsupDocker/app.json new file mode 100644 index 0000000000..febb1f9261 --- /dev/null +++ b/WhatsupDocker/app.json @@ -0,0 +1,11 @@ +{ + "appid": "471b1748546610893a56b7d9254afa4752f630b9", + "name": "What's up Docker", + "website": "https://github.com/getwud/wud", + "license": "MIT License", + "description": "Gets you notified when new versions of your Docker containers are available and lets you react the way you want.", + "enhanced": true, + "tile_background": "dark", + "icon": "whatsupdocker.png", + "sha": "2f0356bc2cafcca5232e02d1283d2a2bd401ef81" +} \ No newline at end of file diff --git a/WhatsupDocker/config.blade.php b/WhatsupDocker/config.blade.php new file mode 100644 index 0000000000..312067075f --- /dev/null +++ b/WhatsupDocker/config.blade.php @@ -0,0 +1,23 @@ +

{{ __('app.apps.config') }} ({{ __('app.optional') }}) @include('items.enable')

+
+
+ + {!! Form::text('config[override_url]', null, array('placeholder' => __('app.apps.override'), 'id' => 'override_url', 'class' => 'form-control')) !!} +
+
+ + {!! Form::text('config[username]', null, array('placeholder' => __('app.apps.username'), 'data-config' => 'username', 'class' => 'form-control config-item')) !!} +
+
+ + {!! Form::input('password', 'config[password]', '', ['placeholder' => __('app.apps.password'), 'data-config' => 'password', 'class' => 'form-control config-item']) !!} +
+
+ + {!! Form::select('config[availablestats][]', \App\SupportedApps\WhatsupDocker\WhatsupDocker::getAvailableStats(), isset($item) ? $item->getConfig()->availablestats ?? null : null, ['multiple' => 'multiple']) !!} +
+
+ +
+
+ diff --git a/WhatsupDocker/livestats.blade.php b/WhatsupDocker/livestats.blade.php new file mode 100644 index 0000000000..66e281342d --- /dev/null +++ b/WhatsupDocker/livestats.blade.php @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/WhatsupDocker/whatsupdocker.png b/WhatsupDocker/whatsupdocker.png new file mode 100644 index 0000000000..b4a5cf70ce Binary files /dev/null and b/WhatsupDocker/whatsupdocker.png differ