diff --git a/Ghostfolio/Ghostfolio.php b/Ghostfolio/Ghostfolio.php new file mode 100644 index 0000000000..dd278f7c46 --- /dev/null +++ b/Ghostfolio/Ghostfolio.php @@ -0,0 +1,123 @@ +auth(); + $perf = $this->getPortfolioPerformance(); + + echo "Successfully communicated with the API"; + } catch (Exception $err) { + echo "Error connecting to Ghostfolio: " . $err->getMessage(); + } + } + + public function url($endpoint) + { + $api_url = parent::normaliseurl($this->config->url) . $endpoint; + return $api_url; + } + + public function auth(): void + { + $body = json_encode(["accessToken" => $this->config->password]); + + $vars = [ + "http_errors" => false, + "timeout" => 5, + "body" => $body, + "headers" => [ + "Content-Type" => "application/json", + ], + ]; + + $result = parent::execute( + $this->url("api/v1/auth/anonymous"), + [], + $vars, + "POST" + ); + + if ($result === null) { + throw new Exception("Could not connect to Ghostfolio"); + } + + $responseBody = $result->getBody()->getContents(); + $response = json_decode($responseBody, true); + if (null === $response || $result->getStatusCode() !== 201 || !isset($response['authToken'])) { + throw new Exception("Error logging in"); + } + + $this->config->jwt = $response['authToken']; + } + + + public function livestats() + { + $this->auth(); + $status = 'inactive'; + + $data = $this->getPortfolioPerformance(); + foreach ($this->config->availablestats as $num => $key) { + $stat = new \stdClass(); + $stat->title = self::getAvailableStats()[$key]; + $value = $data[$key] ?? null; + $stat->value = is_numeric($value) + ? rtrim( + rtrim(number_format($value, 1, decimal_separator: '.', thousands_separator: ''), characters: '0'), + characters: '.' + ) + : substr(string: $value, offset: 0, length: 1); + $details["visiblestats"][] = $stat; + } + return parent::getLiveStats($status, $details); + } + + + + private function getPortfolioPerformance(): mixed + { + $attrs = [ + "headers" => [ + "Content-Type" => "application/json", + "Authorization" => "Bearer " . $this->config->jwt, + ], + "query" => [ + "range" => $this->config->selected_range, + ], + ]; + $result = parent::execute( + $this->url("api/v2/portfolio/performance"), + $attrs, + ); + + if (null === $result || $result->getStatusCode() !== 200) { + throw new Exception("Error retrieving performance"); + } + $data = json_decode($result->getBody()->getContents(), true); + return $data['performance']; + } + + public static function getAvailableStats() + { + return [ + "netPerformancePercentageWithCurrencyEffect" => "Net Perf (%)", + "netPerformanceWithCurrencyEffect" => "Net Perf", + "totalInvestment" => "Invested", + "currentValueInBaseCurrency" => "Value", + "currentNetWorth" => "Net Worth", + ]; + } +} diff --git a/Ghostfolio/app.json b/Ghostfolio/app.json new file mode 100644 index 0000000000..58d6e71628 --- /dev/null +++ b/Ghostfolio/app.json @@ -0,0 +1,10 @@ +{ + "appid": "636e86d7a1a80e47d1ec19e6782e3700227c7603", + "name": "Ghostfolio", + "website": "https://ghostfol.io", + "license": "GNU Affero General Public License v3.0 only", + "description": "test", + "enhanced": true, + "tile_background": "dark", + "icon": "ghostfolio.png" +} \ No newline at end of file diff --git a/Ghostfolio/config.blade.php b/Ghostfolio/config.blade.php new file mode 100644 index 0000000000..8033662955 --- /dev/null +++ b/Ghostfolio/config.blade.php @@ -0,0 +1,31 @@ +

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

+ +
+
+
+ + {!! Form::text('config[override_url]', isset($item) ? $item->getconfig()->override_url : null, ['placeholder' => __('app.apps.override'), 'id' => 'override_url', 'class' => 'form-control']) !!} +
+
+ + {!! Form::input('password', 'config[password]', '', ['placeholder' => __('app.apps.password'), 'data-config' => 'password', 'class' => 'form-control config-item']) !!} +
+
+
+
+ + {!! Form::select( + 'config[selected_range]', + ['1d' => '1 Day', 'wtd' => 'Week To Date', 'ytd' => 'Year To Date', 'max' => 'MAX'], + isset($item) ? $item->getconfig()->selected_range : null, + ['data-config' => 'selected_range', 'class' => 'form-control config-item'], +) !!} +
+
+ + {!! Form::select('config[availablestats][]', App\SupportedApps\Ghostfolio\Ghostfolio::getAvailableStats(), isset($item) ? $item->getConfig()->availablestats ?? null : null, ['multiple' => 'multiple']) !!} +
+ + +
+
\ No newline at end of file diff --git a/Ghostfolio/ghostfolio.png b/Ghostfolio/ghostfolio.png new file mode 100644 index 0000000000..6344026f9c Binary files /dev/null and b/Ghostfolio/ghostfolio.png differ diff --git a/Ghostfolio/livestats.blade.php b/Ghostfolio/livestats.blade.php new file mode 100644 index 0000000000..66e281342d --- /dev/null +++ b/Ghostfolio/livestats.blade.php @@ -0,0 +1,8 @@ + \ No newline at end of file