src/Http/Controllers/Configuration/SeatController.php

Summary

Maintainability
D
1 day
Test Coverage
<?php

/*
 * This file is part of SeAT
 *
 * Copyright (C) 2015 to 2022 Leon Jacobs
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

namespace Seat\Web\Http\Controllers\Configuration;

use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Parsedown;
use Seat\Services\Traits\VersionsManagementTrait;
use Seat\Web\Http\Controllers\Controller;
use Seat\Web\Http\Validation\Customlink;
use Seat\Web\Http\Validation\PackageChangelog;
use Seat\Web\Http\Validation\PackageVersionCheck;
use Seat\Web\Http\Validation\SeatSettings;

/**
 * Class SeatController.
 *
 * @package Seat\Web\Http\Controllers\Configuration
 */
class SeatController extends Controller
{
    use VersionsManagementTrait;

    /**
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
     */
    public function getView()
    {

        $packages = $this->getPluginsMetadataList();

        // Validate SSO Environment settings
        if (is_null(config('esi.eseye_client_id')) or
            is_null(config('esi.eseye_client_secret')) or
            is_null(config('esi.eseye_client_callback'))
        )
            $warn_sso = true;
        else
            $warn_sso = false;

        // Retrieve custom links
        $custom_links = setting('customlinks', true) ?: collect();

        return view('web::configuration.settings.view', compact('packages', 'warn_sso', 'custom_links'));
    }

    /**
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
     */
    public function getAbout()
    {
        $discord_widget = $this->getDiscordWidget();
        $documentation_widget = $this->getDocumentationWidget();
        $github_widget = $this->getGithubWidget();

        return view('web::about.about', compact('discord_widget', 'documentation_widget', 'github_widget'));
    }

    /**
     * @param  \Seat\Web\Http\Validation\SeatSettings  $request
     * @return \Illuminate\Http\RedirectResponse
     *
     * @throws \Seat\Services\Exceptions\SettingException
     */
    public function postUpdateSettings(SeatSettings $request)
    {

        setting(['registration', $request->registration], true);
        setting(['admin_contact', $request->admin_contact], true);
        setting(['allow_tracking', $request->allow_tracking], true);
        setting(['cleanup_data', $request->cleanup_data], true);
        setting(['market_prices_region_id', $request->market_prices_region], true);
        setting(['allow_user_character_unlink', $request->allow_user_character_unlink], true);

        return redirect()->back()
            ->with('success', 'SeAT settings updated!');
    }

    /**
     * @param  \Seat\Web\Http\Validation\Customlink  $request
     * @return \Illuminate\Http\RedirectResponse
     *
     * @throws \Seat\Services\Exceptions\SettingException
     */
    public function postUpdateCustomLinks(Customlink $request)
    {

        // Retrieve the form data.
        $names = $request->input('customlink-name', []);
        $urls = $request->input('customlink-url', []);
        $icons = $request->input('customlink-icon', []);
        $new_tabs = $request->input('customlink-newtab', []);

        // Process the form data.
        $custom_links = collect();

        foreach($names as $key => $name) {
            $custom_links->push((object) [
                'name'    => $name,
                'url'     => $urls[$key],
                'icon'    => $icons[$key],
                'new_tab' => (bool) $new_tabs[$key],
            ]);
        }

        // Update the setting
        setting(['customlinks', $custom_links], true);

        return redirect()->back()
            ->with('success', 'Menu links updated!');
    }

    /**
     * @return \Illuminate\Http\JsonResponse
     */
    public function getApprovedSDE()
    {

        $sde_version = cache()->remember('live_sde_version', 720, function () {

            try {

                $sde_uri = 'https://raw.githubusercontent.com/eveseat/resources/master/sde.json';
                $response = (new Client())->request('GET', $sde_uri);

                // Ensure that the request was successful
                if (! $response->getStatusCode() == 200)
                    return 'Error fetching latest SDE version';

                $json_array = json_decode($response->getBody());

                return $json_array->version;

            } catch (RequestException $e) {

                return 'Error fetching latest SDE version';
            }

        });

        return response()->json(['version' => $sde_version]);
    }

    /**
     * Determine if a package is or not outdated.
     *
     * @param  \Seat\Web\Http\Validation\PackageVersionCheck  $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function postPackagesCheck(PackageVersionCheck $request)
    {
        $latest_version = $this->getPackageLatestVersion($request->input('vendor'), $request->input('package'));

        return response()->json([
            'error' => '',
            'outdated' => version_compare($request->input('version'), $latest_version) < 0,
        ]);
    }

    /**
     * Return the changelog based on provided parameters.
     *
     * @return mixed|string
     *
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function postPackagesChangelog(PackageChangelog $request)
    {
        $changelog_uri = $request->input('uri');
        $changelog_body = $request->input('body');
        $changelog_tag = $request->input('tag');

        if (! is_null($changelog_body) && ! is_null($changelog_tag))
            return $this->getChangelogFromApi($changelog_uri, $changelog_body, $changelog_tag);

        return $this->getChangelogFromFile($changelog_uri);
    }

    /**
     * @return object
     */
    private function getDiscordWidget()
    {
        $discord_widget = cache()->remember('discord_support_widget', 720, function () {

            $discord_widget = [
                'id' => '0',
                'name' => 'SeAT',
                'instant_invite' => '#',
                'presence_count' => 0,
            ];

            try {

                $discord_uri = 'https://discord.com/api/guilds/821361165791133716/widget.json';
                $response = (new Client())->request('GET', $discord_uri);

                // Ensure that the request was successful
                if ($response->getStatusCode() == 200) {
                    $json = json_decode($response->getBody());

                    $discord_widget['id'] = $json->id ?: 0;
                    $discord_widget['name'] = $json->name ?: 'SeAT';
                    $discord_widget['instant_invite'] = $json->instant_invite ?: '#';
                    $discord_widget['presence_count'] = $json->presence_count ?: 0;
                }

                return $discord_widget;

            } catch (Exception $e) {

                logger()->error($e->getMessage(), $e->getTrace());

                return $discord_widget;
            }

        });

        return (object) $discord_widget;
    }

    /**
     * @return object
     */
    private function getDocumentationWidget()
    {
        $docs_widget = cache()->remember('docs_seat_widget', 720, function () {

            $docs_widget = [
                'id' => '0',
                'name' => 'SeAT',
                'url' => 'https://docs.eveseat.net',
                'updated_at' => carbon('now'),
            ];

            try {

                $github_uri = 'https://api.github.com/repos/eveseat/docs';
                $response = (new Client())->request('GET', $github_uri);

                // Ensure that the request was successful
                if ($response->getStatusCode() == 200) {
                    $json = json_decode($response->getBody());

                    $docs_widget['id'] = $json->id ?: 0;
                    $docs_widget['name'] = $json->name ?: 'SeAT';
                    $docs_widget['updated_at'] = carbon($json->pushed_at ?: 'now');
                }

                return $docs_widget;

            } catch (Exception $e) {

                logger()->error($e->getMessage(), $e->getTrace());

                return $docs_widget;
            }

        });

        return (object) $docs_widget;
    }

    /**
     * @return object
     */
    private function getGithubWidget()
    {
        $github_widget = cache()->remember('github_seat_widget', 720, function () {

            $github_widget = [
                'id' => '0',
                'name' => 'SeAT',
                'url' => '#',
                'open_issues' => 0,
            ];

            try {

                $github_uri = 'https://api.github.com/repos/eveseat/seat';
                $response = (new Client())->request('GET', $github_uri);

                // Ensure that the request was successful
                if ($response->getStatusCode() == 200) {
                    $json = json_decode($response->getBody());

                    $github_widget['id'] = $json->id ?: 0;
                    $github_widget['name'] = $json->name ?: 'SeAT';
                    $github_widget['url'] = $json->html_url ?: '#';
                    $github_widget['open_issues'] = $json->open_issues_count ?: 0;
                }

                return $github_widget;

            } catch (Exception $e) {

                logger()->error($e->getMessage(), $e->getTrace());

                return $github_widget;
            }

        });

        return (object) $github_widget;
    }

    /**
     * Return a rendered changelog based on the provided release API endpoint.
     *
     * @param  string  $uri
     * @param  string  $body_attribute
     * @param  string  $tag_attribute
     * @return string
     */
    private function getChangelogFromApi(string $uri, string $body_attribute, string $tag_attribute): string
    {
        try {
            return cache()->remember($this->getChangelogCacheKey($uri), 30, function () use ($uri, $body_attribute, $tag_attribute) {
                $changelog = '';

                // retrieve releases from provided API endpoint
                $client = new Client();
                $response = $client->request('GET', $uri);

                // decode the response
                $json_object = json_decode($response->getBody());

                // spawn a new Markdown parser
                $parser = new Parsedown();
                $parser->setSafeMode(true);

                // iterate over each release and build proper view
                foreach ($json_object as $release) {
                    $changelog .= view('web::configuration.settings.partials.packages.changelog.header', [
                        'version' => $release->{$tag_attribute},
                    ]);

                    $changelog .= view('web::configuration.settings.partials.packages.changelog.body', [
                        'body' => $parser->parse($release->{$body_attribute}),
                    ]);
                }

                // return a rendered release list
                return $changelog;
            });
        } catch (Exception $e) {
            logger()->error('An error occurred while fetching changelog from API.', [
                'code'       => $e->getCode(),
                'error'      => $e->getMessage(),
                'trace'      => $e->getTrace(),
                'uri'        => $uri,
                'attributes' => [
                    'body' => $body_attribute,
                    'tag'  => $tag_attribute,
                ],
            ]);
        }

        return '';
    }

    /**
     * Return parsed markdown from the file located at the provided URI.
     *
     * @param  string  $uri
     * @return mixed
     *
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    private function getChangelogFromFile(string $uri)
    {
        try {
            return cache()->remember($this->getChangelogCacheKey($uri), 30, function () use ($uri) {
                // retrieve changelog from provided uri
                $client = new Client();
                $response = $client->request('GET', $uri);

                // spawn a new Markdown parser
                $parser = new Parsedown();
                $parser->setSafeMode(true);

                // return the parsed changelog
                return $parser->parse($response->getBody());
            });
        } catch (Exception $e) {
            logger()->error('An error occurred while fetching changelog from file.', [
                'code'       => $e->getCode(),
                'error'      => $e->getMessage(),
                'trace'      => $e->getTrace(),
                'uri'        => $uri,
            ]);
        }

        return '';
    }

    /**
     * Determine a valid cache key for the provided URI.
     *
     * @param  string  $uri
     * @return string
     */
    private function getChangelogCacheKey(string $uri)
    {
        return sprintf('changelog.%s', str_replace('=', '', base64_encode($uri)));
    }
}