including some more dashboard components
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\Bookstack;
|
||||
|
||||
class Bookstack extends \App\SupportedApps implements \App\EnhancedApps
|
||||
{
|
||||
public $config;
|
||||
|
||||
//protected $login_first = true; // Uncomment if api requests need to be authed first
|
||||
//protected $method = 'POST'; // Uncomment if requests to the API should be set by POST
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
//$this->jar = new \GuzzleHttp\Cookie\CookieJar; // Uncomment if cookies need to be set
|
||||
}
|
||||
|
||||
public function getHeaders()
|
||||
{
|
||||
$api_token = $this->config->api_token . ":" . $this->config->api_secret;
|
||||
|
||||
$attrs["headers"] = ["Authorization" => "Token " . $api_token];
|
||||
return $attrs;
|
||||
}
|
||||
|
||||
public function test()
|
||||
{
|
||||
$test = parent::appTest(
|
||||
$this->url("api/shelves?count=0"),
|
||||
$this->getHeaders()
|
||||
);
|
||||
echo $test->status;
|
||||
}
|
||||
|
||||
public function livestats()
|
||||
{
|
||||
$status = "inactive";
|
||||
|
||||
$attrs = $this->getHeaders();
|
||||
|
||||
$data = ["visiblestats" => []];
|
||||
|
||||
foreach ($this->config->availablestats as $stat) {
|
||||
if (!isset(self::getAvailableStats()[$stat])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$res = parent::execute(
|
||||
$this->url("api/" . $stat . "?count=0"),
|
||||
$attrs
|
||||
);
|
||||
$details = json_decode($res->getBody());
|
||||
|
||||
$newstat = new \stdClass();
|
||||
$newstat->title = self::getAvailableStats()[$stat];
|
||||
$newstat->value = isset($details->total)
|
||||
? number_format($details->total)
|
||||
: "N/A";
|
||||
|
||||
$data["visiblestats"][] = $newstat;
|
||||
}
|
||||
|
||||
return parent::getLiveStats($status, $data);
|
||||
}
|
||||
|
||||
public function url($endpoint)
|
||||
{
|
||||
$api_url =
|
||||
rtrim(parent::normaliseurl($this->config->url), "/") .
|
||||
"/" .
|
||||
ltrim($endpoint, "/");
|
||||
return $api_url;
|
||||
}
|
||||
|
||||
public static function getAvailableStats()
|
||||
{
|
||||
return [
|
||||
"shelves" => "Shelves",
|
||||
"books" => "Books",
|
||||
"chapters" => "Chapters",
|
||||
"pages" => "Pages",
|
||||
];
|
||||
}
|
||||
}
|
||||
10
stacks/dashboard/config/www/SupportedApps/Bookstack/app.json
Normal file
10
stacks/dashboard/config/www/SupportedApps/Bookstack/app.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "348c49dd03dddd418929316668d2e67bf2d9ae88",
|
||||
"name": "Bookstack",
|
||||
"website": "https://www.bookstackapp.com",
|
||||
"license": "MIT License",
|
||||
"description": "BookStack is a simple, self-hosted, easy-to-use platform for organising and storing information.",
|
||||
"enhanced": true,
|
||||
"tile_background": "dark",
|
||||
"icon": "bookstack.svg"
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<h2>{{ __('app.apps.config') }} ({{ __('app.optional') }}) @include('items.enable')</h2>
|
||||
<div class="items">
|
||||
<div class="input">
|
||||
<label>{{ strtoupper(__('app.url')) }}</label>
|
||||
{!! Form::text('config[override_url]', isset($item) ? $item->getConfig()->override_url ?? null : null, ['placeholder' => __('app.apps.override'), 'id' => 'override_url', 'class' => 'form-control']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>Token ID</label>
|
||||
{!! Form::text('config[api_token]', isset($item) ? $item->getconfig()->api_token : null, ['placeholder' => 'Token ID', 'data-config' => 'api_token', 'class' => 'form-control config-item']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>Token Secret</label>
|
||||
{!! Form::text('config[api_secret]', isset($item) ? $item->getconfig()->api_secret : null, ['placeholder' => 'Token Secret', 'data-config' => 'api_secret', 'class' => 'form-control config-item']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>Stats to show</label>
|
||||
{!! Form::select('config[availablestats][]', App\SupportedApps\Bookstack\Bookstack::getAvailableStats(), isset($item) ? $item->getConfig()->availablestats ?? null : null, ['multiple' => 'multiple']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<button style="margin-top: 32px;" class="btn test" id="test_config">Test</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,8 @@
|
||||
<ul class="livestats">
|
||||
@foreach ($visiblestats as $stat)
|
||||
<li>
|
||||
<span class="title">{!! $stat->title !!}</span>
|
||||
<strong>{!! $stat->value !!}</strong>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\Dockge;
|
||||
|
||||
class Dockge extends \App\SupportedApps
|
||||
{
|
||||
}
|
||||
10
stacks/dashboard/config/www/SupportedApps/Dockge/app.json
Normal file
10
stacks/dashboard/config/www/SupportedApps/Dockge/app.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "0bafb882c9d2c034ca5333367f8ccc90f4ae85e4",
|
||||
"name": "Dockge",
|
||||
"website": "https://github.com/louislam/dockge",
|
||||
"license": "MIT License",
|
||||
"description": "A fancy, easy-to-use and reactive self-hosted docker compose.yaml stack-oriented manager.",
|
||||
"enhanced": false,
|
||||
"tile_background": "dark",
|
||||
"icon": "dockge.svg"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\Dozzle;
|
||||
|
||||
class Dozzle extends \App\SupportedApps
|
||||
{
|
||||
}
|
||||
10
stacks/dashboard/config/www/SupportedApps/Dozzle/app.json
Normal file
10
stacks/dashboard/config/www/SupportedApps/Dozzle/app.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "176d99d897dbd7c02b1a1db4142054f74a76aa47",
|
||||
"name": "Dozzle",
|
||||
"website": "https://dozzle.dev",
|
||||
"license": "MIT License",
|
||||
"description": "Dozzle is a real-time log viewer for docker containers.",
|
||||
"enhanced": false,
|
||||
"tile_background": "dark",
|
||||
"icon": "dozzle.svg"
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\FileBrowser;
|
||||
|
||||
class FileBrowser extends \App\SupportedApps implements \App\EnhancedApps
|
||||
{
|
||||
public $config;
|
||||
|
||||
//protected $login_first = true; // Uncomment if api requests need to be authed first
|
||||
//protected $method = 'POST'; // Uncomment if requests to the API should be set by POST
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
//$this->jar = new \GuzzleHttp\Cookie\CookieJar; // Uncomment if cookies need to be set
|
||||
}
|
||||
|
||||
private function getToken()
|
||||
{
|
||||
$username = $this->config->username;
|
||||
$password = $this->config->password;
|
||||
$authHeader = $this->config->authHeader;
|
||||
|
||||
$attrs = [
|
||||
"headers" => [
|
||||
"Content-Type" => "application/json"
|
||||
],
|
||||
"body" => json_encode([
|
||||
"username" => $username,
|
||||
"password" => $password
|
||||
])
|
||||
];
|
||||
if ($authHeader !== null) {
|
||||
$attrs["headers"][$authHeader] = $username;
|
||||
}
|
||||
|
||||
$res = parent::execute($this->url("api/login"), $attrs, null, "POST");
|
||||
|
||||
switch ($res->getStatusCode()) {
|
||||
case 200:
|
||||
return $res->getBody()->getContents();
|
||||
case 403:
|
||||
throw new \Exception("Invalid username/password");
|
||||
default:
|
||||
throw new \Exception("Could not connect to FileBrowser");
|
||||
}
|
||||
}
|
||||
|
||||
private function formatBytes($bytes, $precision = 2) {
|
||||
$units = array('B', 'KB', 'MB', 'GB', 'TB');
|
||||
$bytes = max($bytes, 0);
|
||||
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
|
||||
$pow = min($pow, count($units) - 1);
|
||||
|
||||
$bytes /= pow(1024, $pow);
|
||||
|
||||
$value = round($bytes, $precision);
|
||||
$unit = $units[$pow];
|
||||
|
||||
return [
|
||||
"value" => $value,
|
||||
"unit" => $unit
|
||||
];
|
||||
}
|
||||
|
||||
public function test()
|
||||
{
|
||||
try {
|
||||
$token = $this->getToken();
|
||||
echo "Successfully communicated with the API";
|
||||
} catch (Exception $err) {
|
||||
echo $err->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
public function livestats()
|
||||
{
|
||||
$status = "inactive";
|
||||
|
||||
$token = $this->getToken();
|
||||
$attrs = [
|
||||
"headers" => [
|
||||
"X-AUTH" => $token
|
||||
],
|
||||
];
|
||||
$res = parent::execute($this->url("api/usage"), $attrs);
|
||||
$details = json_decode($res->getBody());
|
||||
|
||||
if ($details != null) {
|
||||
$data["used"] = $this->formatBytes($details->used);
|
||||
$data["total"] = $this->formatBytes($details->total);
|
||||
}
|
||||
return parent::getLiveStats($status, $data);
|
||||
}
|
||||
|
||||
public function url($endpoint)
|
||||
{
|
||||
$api_url = parent::normaliseurl($this->config->url) . $endpoint;
|
||||
|
||||
return $api_url;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "ba05dd8e070851895ee6184eb9778cfa0753a490",
|
||||
"name": "FileBrowser",
|
||||
"website": "https://github.com/filebrowser/filebrowser",
|
||||
"license": "Apache License 2.0",
|
||||
"description": "filebrowser provides a file managing interface within a specified directory and it can be used to upload, delete, preview, rename and edit your files. It allows the creation of multiple users and each user can have its own directory. It can be used as a standalone app or as a middleware.",
|
||||
"enhanced": true,
|
||||
"tile_background": "dark",
|
||||
"icon": "filebrowser.svg"
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<h2>{{ __('app.apps.config') }} ({{ __('app.optional') }}) @include('items.enable')</h2>
|
||||
<div class="items" style="flex-direction:column">
|
||||
<div style="display:flex;flex-direction:row;">
|
||||
<div class="input">
|
||||
<label>{{ strtoupper(__('app.url')) }}</label>
|
||||
{!! Form::text('config[override_url]', isset($item) ? $item->getconfig()->override_url : null, ['placeholder' => __('app.apps.override'), 'id' => 'override_url', 'class' => 'form-control']) !!}
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;flex-direction:row;">
|
||||
<div class="input">
|
||||
<label>{{ __('app.apps.username') }}</label>
|
||||
{!! Form::text('config[username]', isset($item) ? $item->getconfig()->username : null, ['placeholder' => __('app.apps.username'), 'data-config' => 'username', 'class' => 'form-control config-item']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>{{ __('app.apps.password') }}</label>
|
||||
{!! Form::input('password', 'config[password]', '', ['placeholder' => __('app.apps.password'), 'data-config' => 'password', 'class' => 'form-control config-item']) !!}
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;flex-direction:row;">
|
||||
<div class="input">
|
||||
<label>Proxy Header (<a href="https://filebrowser.org/configuration/authentication-method#proxy-header" target="_blank">help?</a>)</label>
|
||||
{!! Form::text('config[authHeader]', isset($item) ? $item->getconfig()->authHeader : null, ['placeholder' => 'X-My-Header', 'data-config' => 'authHeader', 'class' => 'form-control config-item']) !!}
|
||||
<small>Also fill {{ __('app.apps.username') }}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input">
|
||||
<button style="margin-top: 32px;" class="btn test" id="test_config">Test</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,10 @@
|
||||
<ul class="livestats">
|
||||
<li>
|
||||
<span class="title">Used</span>
|
||||
<strong>{!! $used["value"] !!}<span>{!! $used["unit"] !!}</span></strong>
|
||||
</li>
|
||||
<li>
|
||||
<span class="title">Total</span>
|
||||
<strong>{!! $total["value"] !!}<span>{!! $total["unit"] !!}</span></strong>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\ITTools;
|
||||
|
||||
class ITTools extends \App\SupportedApps
|
||||
{
|
||||
}
|
||||
10
stacks/dashboard/config/www/SupportedApps/ITTools/app.json
Normal file
10
stacks/dashboard/config/www/SupportedApps/ITTools/app.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "b5f16344632fdfe68391a2dc3816ee0edbb1813c",
|
||||
"name": "IT-Tools",
|
||||
"website": "https://it-tools.tech/",
|
||||
"license": "GNU General Public License v3.0 only",
|
||||
"description": "Useful tools for developer and people working in IT.",
|
||||
"enhanced": false,
|
||||
"tile_background": "light",
|
||||
"icon": "ittools.png"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\JDownloader;
|
||||
|
||||
class JDownloader extends \App\SupportedApps
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "af7b37e2841d9150f6abd5a936b32a1f681d6bda",
|
||||
"name": "JDownloader",
|
||||
"website": "http://jdownloader.org",
|
||||
"license": "Creative Commons Attribution Non Commercial Share Alike 2.0 Generic",
|
||||
"description": "JDownloader is a free, open-source download management tool with a huge community of developers that makes downloading as easy and fast as it should be.",
|
||||
"enhanced": false,
|
||||
"tile_background": "dark",
|
||||
"icon": "jdownloader.png"
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\Jellyfin;
|
||||
|
||||
class Jellyfin extends \App\SupportedApps implements \App\EnhancedApps
|
||||
{
|
||||
public $config;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public function test()
|
||||
{
|
||||
$test = parent::appTest(
|
||||
$this->url("System/Info"),
|
||||
$this->getAttrs()
|
||||
);
|
||||
echo $test->status;
|
||||
}
|
||||
|
||||
public function livestats()
|
||||
{
|
||||
$status = "inactive";
|
||||
$res = parent::execute($this->url("Items/Counts"), $this->getAttrs());
|
||||
$result = json_decode($res->getBody());
|
||||
$details = ["visiblestats" => []];
|
||||
foreach ($this->config->availablestats as $stat) {
|
||||
$newstat = new \stdClass();
|
||||
$newstat->title = self::getAvailableStats()[$stat];
|
||||
$newstat->value = $result->{$stat};
|
||||
$details["visiblestats"][] = $newstat;
|
||||
}
|
||||
return parent::getLiveStats($status, $details);
|
||||
}
|
||||
public function url($endpoint)
|
||||
{
|
||||
$api_url = parent::normaliseurl($this->config->url) . $endpoint;
|
||||
return $api_url;
|
||||
}
|
||||
|
||||
private function getAttrs()
|
||||
{
|
||||
$authorizationHeader = "MediaBrowser " .
|
||||
"Token=\"" . urlencode($this->config->password) . "\", " .
|
||||
"Client=\"Heimdall\"";
|
||||
return [
|
||||
"headers" => [
|
||||
"Authorization" => $authorizationHeader,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public static function getAvailableStats()
|
||||
{
|
||||
return [
|
||||
"MovieCount" => "Movies",
|
||||
"SeriesCount" => "Series",
|
||||
"EpisodeCount" => "Episodes",
|
||||
"ArtistCount" => "Artists",
|
||||
"ProgramCount" => "Programs",
|
||||
"TrailerCount" => "Trailers",
|
||||
"SongCount" => "Songs",
|
||||
"AlbumCount" => "Albums",
|
||||
"MusicVideoCount" => "MusicVideos",
|
||||
"BoxSetCount" => "BoxSets",
|
||||
"BookCount" => "Books",
|
||||
"ItemCount" => "Items",
|
||||
];
|
||||
}
|
||||
}
|
||||
10
stacks/dashboard/config/www/SupportedApps/Jellyfin/app.json
Normal file
10
stacks/dashboard/config/www/SupportedApps/Jellyfin/app.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "3e0a7f109bd760b9474c78cb652e8c3e82669226",
|
||||
"name": "Jellyfin",
|
||||
"website": "https://jellyfin.github.io",
|
||||
"license": "GNU General Public License v2.0 only",
|
||||
"description": "Jellyfin is the Free Software Media System that puts you in control of managing and streaming your media. There are no strings attached, no premium licenses or features, and no hidden agendas.",
|
||||
"enhanced": true,
|
||||
"tile_background": "dark",
|
||||
"icon": "jellyfin.svg"
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<h2>{{ __('app.apps.config') }} ({{ __('app.optional') }}) @include('items.enable')</h2>
|
||||
<div class="items">
|
||||
<div class="input">
|
||||
<label>{{ strtoupper(__('app.url')) }}</label>
|
||||
{!! Form::text('config[override_url]', isset($item) ? $item->getconfig()->override_url : null, ['placeholder' => __('app.apps.override'), 'id' => 'override_url', 'class' => 'form-control']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>{{ __('app.apps.password') }} (secret token)</label>
|
||||
{!! Form::input('password', 'config[password]', '', ['placeholder' => __('app.apps.password'), 'data-config' => 'password', 'class' => 'form-control config-item']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>Stats to show</label>
|
||||
{!! Form::select('config[availablestats][]', App\SupportedApps\Jellyfin\Jellyfin::getAvailableStats(), isset($item) ? $item->getConfig()->availablestats ?? null : null, ['multiple' => 'multiple']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<button style="margin-top: 32px;" class="btn test" id="test_config">Test</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,8 @@
|
||||
<ul class="livestats">
|
||||
@foreach ($visiblestats as $stat)
|
||||
<li>
|
||||
<span class="title">{!! $stat->title !!}</span>
|
||||
<strong>{!! $stat->value !!}</strong>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\NginxProxyManager;
|
||||
|
||||
class NginxProxyManager extends \App\SupportedApps implements \App\EnhancedApps
|
||||
{
|
||||
public $config;
|
||||
|
||||
//protected $login_first = true; // Uncomment if api requests need to be authed first
|
||||
//protected $method = 'POST'; // Uncomment if requests to the API should be set by POST
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
//$this->jar = new \GuzzleHttp\Cookie\CookieJar; // Uncomment if cookies need to be set
|
||||
}
|
||||
|
||||
public function test()
|
||||
{
|
||||
$test = parent::appTest($this->url("api"));
|
||||
echo $test->status;
|
||||
}
|
||||
|
||||
public function livestats()
|
||||
{
|
||||
$status = "inactive";
|
||||
$auth_attrs = [
|
||||
"headers" => [
|
||||
"Accept" => "application/json",
|
||||
"Content-Type" => "application/json",
|
||||
],
|
||||
"body" => json_encode([
|
||||
"identity" => $this->config->email,
|
||||
"secret" => $this->config->password,
|
||||
]),
|
||||
];
|
||||
$auth_res = parent::execute(
|
||||
$this->url("api/tokens"),
|
||||
$auth_attrs,
|
||||
null,
|
||||
"POST"
|
||||
);
|
||||
$auth_data = json_decode($auth_res->getBody(), true);
|
||||
$token = $auth_data["token"];
|
||||
|
||||
$attrs = [
|
||||
"headers" => [
|
||||
"Accept" => "application/json",
|
||||
"Authorization" => "Bearer " . $token,
|
||||
],
|
||||
];
|
||||
$res = parent::execute($this->url("api/reports/hosts"), $attrs);
|
||||
$data = json_decode($res->getBody(), true);
|
||||
|
||||
return parent::getLiveStats($status, $data);
|
||||
}
|
||||
public function url($endpoint)
|
||||
{
|
||||
$api_url = parent::normaliseurl($this->config->url) . $endpoint;
|
||||
return $api_url;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "cbfad988a16a9fbcc1812bc206afcc1f73dd36de",
|
||||
"name": "Nginx Proxy Manager",
|
||||
"website": "https://nginxproxymanager.jc21.com",
|
||||
"license": "MIT License",
|
||||
"description": "This project comes as a pre-built docker image that enables you to easily forward to your websites running at home or otherwise, including free SSL, without having to know too much about Nginx or Letsencrypt.",
|
||||
"enhanced": true,
|
||||
"tile_background": "light",
|
||||
"icon": "nginxproxymanager.png"
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<h2>{{ __('app.apps.config') }} ({{ __('app.optional') }}) @include('items.enable')</h2>
|
||||
<div class="items">
|
||||
<div class="input">
|
||||
<label>{{ strtoupper(__('app.url')) }}</label>
|
||||
{!! Form::text('config[override_url]', isset($item) ? $item->getconfig()->override_url : null, ['placeholder' => __('app.apps.override'), 'id' => 'override_url', 'class' => 'form-control']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>Email address</label>
|
||||
{!! Form::text('config[email]', isset($item) ? $item->getconfig()->email : null, ['placeholder' => __('Email address'), 'data-config' => 'email', 'class' => 'form-control config-item']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>{{ __('app.apps.password') }}</label>
|
||||
{!! Form::input('password', 'config[password]', '', ['placeholder' => __('app.apps.password'), 'data-config' => 'password', 'class' => 'form-control config-item']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<button style="margin-top: 32px;" class="btn test" id="test_config">Test</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,10 @@
|
||||
<ul class="livestats">
|
||||
<li>
|
||||
<span class="title">Proxy Hosts</span>
|
||||
<strong>{!! $proxy !!}</strong>
|
||||
</li>
|
||||
<li>
|
||||
<span class="title">Redirection Hosts</span>
|
||||
<strong>{!! $redirection !!}</strong>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\OnlyOffice;
|
||||
|
||||
class OnlyOffice extends \App\SupportedApps
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "fc4e407d69510b855b678aa4fba6083fbbfc5383",
|
||||
"name": "OnlyOffice",
|
||||
"website": "https://www.onlyoffice.com",
|
||||
"license": "GNU Affero General Public License v3.0 or later",
|
||||
"description": "ONLYOFFICE online editors for text documents, spreadsheets, and presentations with access to pro features and connect them to the platform of your choice with ready-to-use connectors: https://www.onlyoffice.com/download.aspx#connectors",
|
||||
"enhanced": false,
|
||||
"tile_background": "light",
|
||||
"icon": "onlyoffice.png"
|
||||
}
|
||||
184
stacks/dashboard/config/www/SupportedApps/Pihole/Pihole.php
Normal file
184
stacks/dashboard/config/www/SupportedApps/Pihole/Pihole.php
Normal file
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\Pihole;
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class Pihole extends \App\SupportedApps implements \App\EnhancedApps
|
||||
{
|
||||
public $config;
|
||||
|
||||
//protected $login_first = true; // Uncomment if api requests need to be authed first
|
||||
//protected $method = 'POST'; // Uncomment if requests to the API should be set by POST
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->jar = new \GuzzleHttp\Cookie\CookieJar(); // Uncomment if cookies need to be set
|
||||
}
|
||||
|
||||
public function test()
|
||||
{
|
||||
$version = $this->config->version;
|
||||
|
||||
if ($version == 5) {
|
||||
$test = parent::appTest($this->url("api.php?summaryRaw"));
|
||||
echo $test->status;
|
||||
}
|
||||
if ($version == 6) {
|
||||
$test = $this->getInfo();
|
||||
if ($test["valid"]) {
|
||||
echo "Successfully communicated with the API";
|
||||
} else {
|
||||
echo "Error while communicating with the API: " . $test["message"];
|
||||
}
|
||||
}
|
||||
}
|
||||
public function livestats()
|
||||
{
|
||||
$data = [];
|
||||
$status = "inactive";
|
||||
$version = $this->config->version;
|
||||
|
||||
if ($version == 5) {
|
||||
$res = parent::execute($this->url("api.php?summaryRaw"));
|
||||
$details = json_decode($res->getBody());
|
||||
if ($details) {
|
||||
$data["ads_blocked"] = number_format(
|
||||
$details->ads_blocked_today
|
||||
);
|
||||
$data["ads_percentage"] = number_format(
|
||||
$details->ads_percentage_today,
|
||||
1
|
||||
);
|
||||
|
||||
$status = "active";
|
||||
}
|
||||
}
|
||||
|
||||
if ($version == 6) {
|
||||
$results = $this->getInfo();
|
||||
|
||||
if ($results["valid"]) {
|
||||
$data["ads_blocked"] = $results["queries"];
|
||||
$data["ads_percentage"] = $results["percent"];
|
||||
|
||||
$status = "active";
|
||||
}
|
||||
}
|
||||
return parent::getLiveStats($status, $data);
|
||||
}
|
||||
|
||||
public function url($endpoint)
|
||||
{
|
||||
$version = $this->config->version;
|
||||
if ($version == 5) {
|
||||
$apikey = $this->config->apikey;
|
||||
$api_url = parent::normaliseurl($this->config->url) . $endpoint;
|
||||
|
||||
if ($apikey) {
|
||||
$api_url .= "&auth=" . $apikey;
|
||||
}
|
||||
}
|
||||
if ($version == 6) {
|
||||
$api_url = parent::normaliseurl($this->config->url) . $endpoint;
|
||||
}
|
||||
return $api_url;
|
||||
}
|
||||
|
||||
public function getInfo()
|
||||
{
|
||||
$ignoreTls = $this->getConfigValue("ignore_tls", false);
|
||||
if ($ignoreTls) {
|
||||
$attrs = [
|
||||
"body" => json_encode(['password' => $this->config->apikey]),
|
||||
"cookies" => $this->jar,
|
||||
"verify" => false,
|
||||
"headers" => [
|
||||
"Content-Type" => "application/json",
|
||||
"Accept" => "application/json",
|
||||
],
|
||||
];
|
||||
$attrsid["verify"] = false;
|
||||
} else {
|
||||
$attrs = [
|
||||
"body" => json_encode(['password' => $this->config->apikey]),
|
||||
"cookies" => $this->jar,
|
||||
"headers" => [
|
||||
"Content-Type" => "application/json",
|
||||
"Accept" => "application/json",
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
// Create session and retrieve data
|
||||
$response = parent::execute($this->url("api/auth"), $attrs, null, "POST");
|
||||
$auth = json_decode($response->getBody());
|
||||
|
||||
if (!$auth->session->valid) {
|
||||
$data = [
|
||||
'valid' => false,
|
||||
'validity' => -1,
|
||||
'message' => $auth->session->message,
|
||||
'queries' => 0,
|
||||
'percent' => 0
|
||||
];
|
||||
return $data;
|
||||
}
|
||||
|
||||
if ($ignoreTls) {
|
||||
$attrsid = [
|
||||
"body" => json_encode(['sid' => $auth->session->sid]),
|
||||
"cookies" => $this->jar,
|
||||
"verify" => false,
|
||||
"headers" => [
|
||||
"Content-Type" => "application/json",
|
||||
"Accept" => "application/json",
|
||||
],
|
||||
];
|
||||
} else {
|
||||
$attrsid = [
|
||||
"body" => json_encode(['sid' => $auth->session->sid]),
|
||||
"cookies" => $this->jar,
|
||||
"headers" => [
|
||||
"Content-Type" => "application/json",
|
||||
"Accept" => "application/json",
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
// Get queries data
|
||||
$responsesummary = parent::execute($this->url("api/stats/summary"), $attrsid, null, "GET");
|
||||
$datasummary = json_decode($responsesummary->getBody());
|
||||
|
||||
// After retrieving the data the session is closed to declutter
|
||||
parent::execute($this->url("api/auth"), $attrsid, null, "DELETE");
|
||||
|
||||
// Extract data from the response
|
||||
$valid = $auth->session->valid;
|
||||
$validity = $auth->session->validity;
|
||||
$message = $auth->session->message;
|
||||
|
||||
if (!$auth->session->valid) {
|
||||
$queriesblocked = 0;
|
||||
$percentblocked = 0;
|
||||
} else {
|
||||
$queriesblocked = $datasummary->queries->blocked;
|
||||
$percentblocked = round($datasummary->queries->percent_blocked, 2);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'valid' => $valid,
|
||||
'validity' => $validity,
|
||||
'message' => $message,
|
||||
'queries' => $queriesblocked,
|
||||
'percent' => $percentblocked
|
||||
];
|
||||
return $data;
|
||||
}
|
||||
public function getConfigValue($key, $default = null)
|
||||
{
|
||||
return isset($this->config) && isset($this->config->$key)
|
||||
? $this->config->$key
|
||||
: $default;
|
||||
}
|
||||
}
|
||||
10
stacks/dashboard/config/www/SupportedApps/Pihole/app.json
Normal file
10
stacks/dashboard/config/www/SupportedApps/Pihole/app.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "b89920409bdce40e08ba1023480b0546061cd577",
|
||||
"name": "Pi-hole",
|
||||
"website": "https://pi-hole.net",
|
||||
"license": "European Union Public License 1.2",
|
||||
"description": "Pi-hole is a Linux network-level advertisement and internet tracker blocking application which acts as a DNS sinkhole, intended for use on a private network.",
|
||||
"enhanced": true,
|
||||
"tile_background": "dark",
|
||||
"icon": "pihole.svg"
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<h2>{{ __('app.apps.config') }} ({{ __('app.optional') }}) @include('items.enable')</h2>
|
||||
<div class="items">
|
||||
<input type="hidden" data-config="dataonly" class="config-item" name="config[dataonly]" value="1" />
|
||||
<div class="input">
|
||||
<label>{{ strtoupper(__('app.url')) }}</label>
|
||||
{!! Form::text('config[override_url]', isset($item) ? $item->getconfig()->override_url : null, ['placeholder' => __('app.apps.override'), 'id' => 'override_url', 'class' => 'form-control']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>Api Key(v5)/App Password(v6)</label>
|
||||
{!! Form::text('config[apikey]', isset($item) && property_exists($item->getconfig(), 'apikey') ? $item->getconfig()->apikey : null, ['placeholder' => __('app.apps.apikey'), 'data-config' => 'apikey', 'class' => 'form-control config-item']) !!}
|
||||
</div>
|
||||
<div class="items" style="max-width: 100px;">
|
||||
<div class="input">
|
||||
<label>Version</label>
|
||||
{!! Form::select(
|
||||
'config[version]',
|
||||
['5' => 'v5', '6' => 'v6'],
|
||||
isset($item) ? $item->getconfig()->version : null,
|
||||
['data-config' => 'version', 'class' => 'form-control config-item'],
|
||||
) !!}
|
||||
</div>
|
||||
</div>
|
||||
<div class="input" style="max-width: 150px;">
|
||||
<label>Skip TLS verification</label>
|
||||
<div class="toggleinput" style="margin-top: 26px; padding-left: 15px;">
|
||||
{!! Form::hidden('config[ignore_tls]', 0, ['class' => 'config-item', 'data-config' => 'ignore_tls']) !!}
|
||||
<label class="switch">
|
||||
<?php
|
||||
$checked = false;
|
||||
if (isset($item) && !empty($item) && isset($item->getconfig()->ignore_tls)) {
|
||||
$checked = $item->getconfig()->ignore_tls;
|
||||
}
|
||||
$set_checked = $checked ? ' checked="checked"' : '';
|
||||
?>
|
||||
<input type="checkbox" class="config-item" data-config="ignore_tls" name="config[ignore_tls]" value="1" <?php echo $set_checked; ?> />
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input">
|
||||
<button style="margin-top: 32px;" class="btn test" id="test_config">Test</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,10 @@
|
||||
<ul class="livestats">
|
||||
<li>
|
||||
<span class="title">Queries<br />Blocked</span>
|
||||
<strong>{!! $ads_blocked !!}</strong>
|
||||
</li>
|
||||
<li>
|
||||
<span class="title">Percent<br /> Blocked</span>
|
||||
<strong>{!! $ads_percentage !!}</strong>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\UptimeKuma;
|
||||
|
||||
class UptimeKuma extends \App\SupportedApps implements \App\EnhancedApps
|
||||
{
|
||||
public $config;
|
||||
|
||||
private $mapping = [
|
||||
0 => "down",
|
||||
1 => "up",
|
||||
2 => "pending",
|
||||
3 => "maintenance",
|
||||
];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
private function getAttrs()
|
||||
{
|
||||
if (empty($this->config->apikey)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$basicAuthValue = base64_encode(":" . $this->config->apikey);
|
||||
|
||||
return [
|
||||
"headers" => [
|
||||
"Authorization" => "Basic " . $basicAuthValue,
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function test()
|
||||
{
|
||||
|
||||
$test = parent::appTest($this->url("metrics"), $this->getAttrs());
|
||||
echo $test->status;
|
||||
}
|
||||
|
||||
public function livestats()
|
||||
{
|
||||
$status = "inactive";
|
||||
|
||||
$response = parent::execute($this->url("metrics"), $this->getAttrs());
|
||||
$body = $response->getBody();
|
||||
|
||||
$lines = explode("\n", $body);
|
||||
|
||||
$data = [
|
||||
"up" => 0,
|
||||
"down" => 0,
|
||||
"pending" => 0,
|
||||
"maintenance" => 0,
|
||||
"unknown" => 0,
|
||||
];
|
||||
|
||||
foreach ($lines as $line) {
|
||||
if (strlen($line) === 0 || strpos($line, '#') === 0) {
|
||||
// If the line is empty or is a comment we can skip it
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strpos($line, 'monitor_status') !== 0) {
|
||||
// If the line is a metric but not a monitor we can ignore it
|
||||
continue;
|
||||
}
|
||||
|
||||
// We only really care about the state, which is the integer at the end
|
||||
// of the line.
|
||||
//
|
||||
// This can be 0 (Down), 1 (Up), 2 (Pending), 3 (Maintenance)
|
||||
//
|
||||
// We only care about the down or up but let's translate all of them.
|
||||
$state = intval(substr($line, strrpos($line, ' ')));
|
||||
|
||||
$data[$this->mapping[$state] ?? 'unknown']++;
|
||||
}
|
||||
|
||||
if ($data["down"] > 0) {
|
||||
$status = "active";
|
||||
}
|
||||
|
||||
return parent::getLiveStats($status, $data);
|
||||
}
|
||||
|
||||
public function url($endpoint)
|
||||
{
|
||||
$api_url = parent::normaliseurl($this->config->url) .
|
||||
$endpoint;
|
||||
|
||||
return $api_url;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "366c6646eedab83cc4b349f198424d2291cbfa76",
|
||||
"name": "Uptime Kuma",
|
||||
"website": "https://uptime.kuma.pet",
|
||||
"license": "MIT License",
|
||||
"description": "It is a self-hosted monitoring tool like \"Uptime Robot\".",
|
||||
"enhanced": true,
|
||||
"tile_background": "dark",
|
||||
"icon": "uptimekuma.svg"
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<h2>{{ __('app.apps.config') }} ({{ __('app.optional') }}) @include('items.enable')</h2>
|
||||
<div class="items">
|
||||
<input type="hidden" data-config="dataonly" class="config-item" name="config[dataonly]" value="1" />
|
||||
<div class="input">
|
||||
<label>{{ strtoupper(__('app.url')) }}</label>
|
||||
{!! Form::text('config[override_url]', isset($item) ? $item->getconfig()->override_url : null, ['placeholder' => __('app.apps.override'), 'id' => 'override_url', 'class' => 'form-control']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>{{ __('app.apps.apikey') }}</label>
|
||||
{!! Form::text('config[apikey]', isset($item) ? ($item->getconfig()->apikey ?? null) : null, ['placeholder' => __('app.apps.apikey'), 'data-config' => 'apikey', 'class' => 'form-control config-item']) !!}
|
||||
</div>
|
||||
<div class="input">
|
||||
<label>Skip TLS verification</label>
|
||||
<div class="toggleinput" style="margin-top: 26px; padding-left: 15px;">
|
||||
{!! Form::hidden('config[ignore_tls]', 0, ['class' => 'config-item', 'data-config' => 'ignore_tls']) !!}
|
||||
<label class="switch">
|
||||
<?php
|
||||
$checked = false;
|
||||
if (isset($item) && !empty($item) && isset($item->getconfig()->ignore_tls)) {
|
||||
$checked = $item->getconfig()->ignore_tls;
|
||||
}
|
||||
$set_checked = $checked ? ' checked="checked"' : '';
|
||||
?>
|
||||
<input type="checkbox" class="config-item" data-config="ignore_tls" name="config[ignore_tls]" value="1" <?php echo $set_checked; ?> />
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input">
|
||||
<button style="margin-top: 32px;" class="btn test" id="test_config">Test</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,10 @@
|
||||
<ul class="livestats">
|
||||
<li>
|
||||
<span class="title">Up</span>
|
||||
<strong>{!! $up ?? 0 !!}</strong>
|
||||
</li>
|
||||
<li>
|
||||
<span class="title">Down</span>
|
||||
<strong>{!! $down ?? 0 !!}</strong>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\Vaultwarden;
|
||||
|
||||
class Vaultwarden extends \App\SupportedApps
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "ddf4f264320af1347ef54d424c60fae3b4fcc448",
|
||||
"name": "Vaultwarden",
|
||||
"website": "https://github.com/dani-garcia/vaultwarden",
|
||||
"license": "GNU Affero General Public License v3.0",
|
||||
"description": "Alternative implementation of the Bitwarden server API written in Rust and compatible with upstream Bitwarden clients*, perfect for self-hosted deployment where running the official resource-heavy service might not be ideal.",
|
||||
"enhanced": false,
|
||||
"tile_background": "light",
|
||||
"icon": "vaultwarden.png"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\WireGuard;
|
||||
|
||||
class WireGuard extends \App\SupportedApps
|
||||
{
|
||||
}
|
||||
10
stacks/dashboard/config/www/SupportedApps/WireGuard/app.json
Normal file
10
stacks/dashboard/config/www/SupportedApps/WireGuard/app.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "afef2217e82ee20638490bb102605f6e09789093",
|
||||
"name": "WireGuard",
|
||||
"website": "https://www.wireguard.com",
|
||||
"license": "CNRI Python Open Source GPL Compatible License Agreement",
|
||||
"description": "WireGuard® is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography. It aims to be faster, simpler, leaner, and more useful than IPsec, while avoiding the massive headache. It intends to be considerably more performant than OpenVPN. WireGuard is designed as a general purpose VPN for running on embedded interfaces and super computers alike, fit for many different circumstances. Initially released for the Linux kernel, it is now cross-platform (Windows, macOS, BSD, iOS, Android) and widely deployable. It is currently under heavy development, but already it might be regarded as the most secure, easiest to use, and simplest VPN solution in the industry.",
|
||||
"enhanced": false,
|
||||
"tile_background": "dark",
|
||||
"icon": "wireguard.png"
|
||||
}
|
||||
10
stacks/dashboard/config/www/SupportedApps/ownCloud/app.json
Normal file
10
stacks/dashboard/config/www/SupportedApps/ownCloud/app.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"appid": "668b5fcda851fe516fef14e82973beffe32f385a",
|
||||
"name": "ownCloud",
|
||||
"website": "https://owncloud.org",
|
||||
"license": "GNU Affero General Public License v3.0 or later",
|
||||
"description": "ownCloud is a free and open source file hosting service. It also supports extensions for online document editing, calendar and contact synchronization. It's a safe home for all your data.",
|
||||
"enhanced": false,
|
||||
"tile_background": "dark",
|
||||
"icon": "owncloud.png"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace App\SupportedApps\ownCloud;
|
||||
|
||||
class ownCloud extends \App\SupportedApps // phpcs:ignore
|
||||
{
|
||||
}
|
||||
Reference in New Issue
Block a user