<?php

namespace DevGroup\ExtensionsManager\controllers;

use DevGroup\AdminUtils\controllers\BaseController;
use DevGroup\DeferredTasks\actions\ReportQueueItem;
use DevGroup\DeferredTasks\helpers\DeferredHelper;
use DevGroup\DeferredTasks\helpers\ReportingChain;
use DevGroup\ExtensionsManager\actions\ConfigurationIndex;
use DevGroup\ExtensionsManager\ExtensionsManager;
use DevGroup\ExtensionsManager\helpers\ExtensionDataHelper;
use DevGroup\ExtensionsManager\models\Extension;
use Packagist\Api\Client;
use Yii;
use yii\base\InvalidParamException;
use yii\data\ArrayDataProvider;
use yii\helpers\Json;
use yii\web\ForbiddenHttpException;
use yii\web\NotFoundHttpException;
use yii\web\Response;
use yii\web\ServerErrorHttpException;

class ExtensionsController extends BaseController
{
    /** @var  Client packagist.org API client instance */
    private static $packagist;

    /**
     * @inheritdoc
     */
    public function actions()
    {
        return [
            'config' => [
                'class' => ConfigurationIndex::className(),
            ],
            'deferred-report-queue-item' => [
                'class' => ReportQueueItem::className(),
            ],
        ];
    }

    public function behaviors()
    {
        return [
            'accessControl' => [
                'class' => '\yii\filters\AccessControl',
                'rules' => [
                    [
                        'allow' => true,
                        'actions' => ['index', 'details', 'deferred-report-queue-item', 'search', 'run-task'],
                        'roles' => ['extensions-manager-view-extensions'],
                    ],
                    [
                        'allow' => true,
                        'actions' => ['config'],
                        'roles' => ['extensions-manager-configure-extension'],
                    ],
                    [
                        'allow' => false,
                        'roles' => ['*'],
                    ]
                ],
            ],
        ];
    }

    /**
     *Shows installed extensions
     */
    public function actionIndex()
    {
        $extensions = ExtensionsManager::module()->getExtensions();
        return $this->render(
            'index',
            [
                'dataProvider' => new ArrayDataProvider([
                    'allModels' => $extensions,
                    'sort' => [
                        'attributes' => ['composer_name', 'composer_type', 'is_active'],
                    ],
                    'pagination' => [
                        'defaultPageSize' => 10,
                        'pageSize' => ExtensionsManager::module()->extensionsPerPage,
                    ],
                ]),
            ]
        );
    }

    /**
     * Searching extensions packages using packagist API.
     * Pckagist API gives us ability to filter packages by type and vendor.
     * Supported types are: Extension::getTypes();
     * Vendor filter extracts from query string. If query string contains / or \ all string before it will be
     * recognized as vendor and added into API query.
     *
     * @param string $sort
     * @param string $type
     * @param string $query
     * @return \DevGroup\AdminUtils\response\AjaxResponse|string
     */
    public function actionSearch($sort = '', $type = Extension::TYPE_DOTPLANT, $query = '')
    {
        $packagist = self::getPackagist();
        $type = empty($type) ? Extension::TYPE_DOTPLANT : $type;
        $filters = ['type' => $type];
        if (1 === preg_match('{([\\\\/])}', $query, $m)) {
            $queryArray = explode($m[0], $query);
            $filters['vendor'] = array_shift($queryArray);
        }
        $packages = $packagist->search($query, $filters);
        return $this->renderResponse(
            'search',
            [
                'dataProvider' => new ArrayDataProvider([
                    'allModels' => $packages,
                    'pagination' => [
                        'defaultPageSize' => 10,
                        'pageSize' => ExtensionsManager::module()->extensionsPerPage,
                    ],
                ]),
                'type' => $type,
            ]
        );
    }

    /**
     * Process API requests to github and packagist
     *
     * @param $url
     * @param array $headers
     * @return mixed
     */
    private static function doRequest($url, $headers = [])
    {
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        $response = curl_exec($ch);
        if (0 !== $errno = curl_errno($ch)) {
            $errorMessage = curl_strerror($errno);
            Yii::$app->session->setFlash("cURL error ({$errno}):\n {$errorMessage}");
        }
        curl_close($ch);
        return $response;
    }

    /**
     * @return Client
     */
    private static function getPackagist()
    {
        if (true === empty(self::$packagist) || false === self::$packagist instanceof Client) {
            $packagist = new Client();
            $packagist->setPackagistUrl(ExtensionsManager::module()->packagistUrl);
            self::$packagist = $packagist;
        }
        return self::$packagist;
    }

    /**
     * @param $repo
     * @return bool
     */
    public static function isGit($repo)
    {
        return false !== strpos($repo, 'github');
    }

    /**
     * Method collects an extended package data from packagist.org and github.com
     * other services are not supported yet.
     *
     * @return \DevGroup\AdminUtils\response\AjaxResponse|string
     * @throws NotFoundHttpException
     */
    public function actionDetails()
    {
        if (false === Yii::$app->request->isAjax) {
            throw new NotFoundHttpException("Page not found");
        }
        $module = ExtensionsManager::module();
        $packageName = Yii::$app->request->post('packageName');
        $packagist = self::getPackagist();
        $package = $packagist->get($packageName);
        $repository = $package->getRepository();
        $packagistVersions = $package->getVersions();
        $readme = '';
        $versionsData = $dependencies = [];
        if (true === self::isGit($repository)) {
            $repository = preg_replace(['%^.*github.com\/%', '%\.git$%'], '', $repository);
            $gitAccessToken = $module->githubAccessToken;
            $gitApiUrl = rtrim($module->githubApiUrl, '/');
            $applicationName = $module->applicationName;
            $headers = [
                'User-Agent: ' . $applicationName,
            ];
            if (false === empty($gitAccessToken)) {
                $headers[] = 'Authorization: token ' . $gitAccessToken;
            }
            $gitReadmeUrl = $gitApiUrl . '/repos/' . $repository . '/readme';
            $gitReleasesUrl = $gitApiUrl . '/repos/' . $repository . '/releases';
            $readmeData = self::doRequest($gitReadmeUrl, $headers);
            $readme = ExtensionDataHelper::humanizeReadme($readmeData);
            $versionsData = Json::decode(self::doRequest($gitReleasesUrl, $headers));
            if (true === empty($versionsData)) {
                $gitTagsUrl = $gitApiUrl . '/repos/' . $repository . '/tags';
                $versionsData = Json::decode(self::doRequest($gitTagsUrl, $headers));
            }
        }
        //ExtensionDataHelper::getVersions() must be invoked before other methods who fetches versioned data
        $versions = ExtensionDataHelper::getVersions($packagistVersions, array_shift($versionsData));
        $jsonUrl = rtrim($module->packagistUrl, '/') . '/packages/' . trim($packageName, '/ ') . '.json';
        $packageJson = self::doRequest($jsonUrl);
        $packageData = Json::decode($packageJson);
        $type = ExtensionDataHelper::getType($packageData);

        return $this->renderResponse(
            '_ext-details',
            [
                'readme' => $readme,
                'versions' => $versions,
                'description' => ExtensionDataHelper::getLocalizedVersionedDataField(
                    $packageData,
                    Extension::TYPE_YII,
                    'description'
                ),
                'name' => ExtensionDataHelper::getLocalizedVersionedDataField(
                    $packageData,
                    Extension::TYPE_YII,
                    'name'
                ),
                'dependencies' => [
                    'require' => ExtensionDataHelper::getOtherPackageVersionedData($packageData, 'require'),
                    'require-dev' => ExtensionDataHelper::getOtherPackageVersionedData($packageData, 'require-dev'),
                ],
                'authors' => ExtensionDataHelper::getOtherPackageVersionedData($packageData, 'authors'),
                'license' => ExtensionDataHelper::getOtherPackageVersionedData($packageData, 'license'),
                'packageName' => $packageName,
                'installed' => array_key_exists($packageName, $module->getExtensions()),
                'type' => $type,
            ]
        );
    }

    /**
     * Common method to access from web via ajax requests. Builds a ReportingChain and immediately fires it.
     *
     * @return array
     * @throws NotFoundHttpException
     * @throws ServerErrorHttpException
     * @throws InvalidParamException
     */
    public function actionRunTask()
    {
        if (false === Yii::$app->request->isAjax) {
            throw new NotFoundHttpException('Page not found');
        }
        $module = ExtensionsManager::module();
        $packageName = Yii::$app->request->post('packageName');
        $extension = $module->getExtensions($packageName);
        $taskType = Yii::$app->request->post('taskType');
        if (true === empty($extension) && $taskType != ExtensionsManager::INSTALL_DEFERRED_TASK) {
            return self::runTask(
                [
                    realpath(Yii::getAlias('@app') . '/yii'),
                    'extension/dummy',
                    'Undefined extension: ' . $packageName,
                ],
                ExtensionsManager::EXTENSION_DUMMY_DEFERRED_GROUP
            );
        }
        if ($module->extensionIsCore($packageName)
            && !Yii::$app->user->can('extensions-manager-access-to-core-extension')
        ) {
            throw new ForbiddenHttpException;
        }
        $chain = new ReportingChain();
        switch ($taskType) {
            case ExtensionsManager::INSTALL_DEFERRED_TASK :
                if ($module->extensionIsCore($packageName)
                    || !Yii::$app->user->can('extensions-manager-install-extension')
                ) {
                    throw new ForbiddenHttpException;
                }
                return self::runTask(
                    [
                        $module->composerPath,
                        'require',
                        $packageName,
                        '--no-interaction',
                        '--no-ansi',
                        "--working-dir={$module->getLocalExtensionsPath()}",
                        '--prefer-dist',
                        '-o',
                        $module->verbose == 1 ? '-vvv' : '',
                    ],
                    ExtensionsManager::COMPOSER_INSTALL_DEFERRED_GROUP
                );
            case ExtensionsManager::UNINSTALL_DEFERRED_TASK :
                if ($module->extensionIsCore($packageName)
                    || !Yii::$app->user->can('extensions-manager-uninstall-extension')
                ) {
                    throw new ForbiddenHttpException;
                }
                self::uninstall($extension, $chain);
                break;
            case ExtensionsManager::ACTIVATE_DEFERRED_TASK :
                if (!Yii::$app->user->can('extensions-manager-activate-extension')) {
                    throw new ForbiddenHttpException;
                }
                self::activate($extension, $chain);
                break;
            case ExtensionsManager::DEACTIVATE_DEFERRED_TASK :
                if (!Yii::$app->user->can('extensions-manager-deactivate-extension')) {
                    throw new ForbiddenHttpException;
                }
                self::deactivate($extension, $chain);
                break;
            default:
                return self::runTask(
                    [
                        realpath(Yii::getAlias('@app') . '/yii'),
                        'extension/dummy',
                        'Unrecognized task!',
                    ],
                    ExtensionsManager::EXTENSION_DUMMY_DEFERRED_GROUP
                );
        }
        if (null !== $firstTaskId = $chain->registerChain()) {
            DeferredHelper::runImmediateTask($firstTaskId);
            Yii::$app->response->format = Response::FORMAT_JSON;
            return [
                'queueItemId' => $firstTaskId,
            ];
        } else {
            throw new ServerErrorHttpException("Unable to start chain");
        }
    }

    /**
     * Adds deactivation task into ReportingChain if Extension is active
     *
     * @param array $extension
     * @param ReportingChain $chain
     */
    private static function deactivate($extension, ReportingChain $chain)
    {
        if ($extension['is_active'] == 1) {
            ExtensionDataHelper::prepareMigrationTask(
                $extension,
                $chain,
                ExtensionsManager::MIGRATE_TYPE_DOWN,
                ExtensionsManager::EXTENSION_DEACTIVATE_DEFERRED_GROUP
            );
            $deactivationTask = ExtensionDataHelper::buildTask(
                [
                    realpath(Yii::getAlias('@app') . '/yii'),
                    'extension/deactivate',
                    $extension['composer_name'],
                ],
                ExtensionsManager::EXTENSION_DEACTIVATE_DEFERRED_GROUP
            );
            $chain->addTask($deactivationTask);
        } else {
            $dummyTask = ExtensionDataHelper::buildTask(
                [
                    realpath(Yii::getAlias('@app') . '/yii'),
                    'extension/dummy',
                    'Extension already deactivated!',
                ],
                ExtensionsManager::EXTENSION_DUMMY_DEFERRED_GROUP
            );
            $chain->addTask($dummyTask);
        }
    }

    /**
     * Adds activation task into ReportingChain if Extension is not active
     *
     * @param array $extension
     * @param ReportingChain $chain
     */
    private static function activate($extension, ReportingChain $chain)
    {
        if ($extension['is_active'] == 0) {
            ExtensionDataHelper::prepareMigrationTask(
                $extension,
                $chain,
                ExtensionsManager::MIGRATE_TYPE_UP,
                ExtensionsManager::EXTENSION_ACTIVATE_DEFERRED_GROUP
            );
            $activationTask = ExtensionDataHelper::buildTask(
                [
                    realpath(Yii::getAlias('@app') . '/yii'),
                    'extension/activate',
                    $extension['composer_name'],
                ],
                ExtensionsManager::EXTENSION_ACTIVATE_DEFERRED_GROUP
            );
            $chain->addTask($activationTask);
        } else {
            $dummyTask = ExtensionDataHelper::buildTask(
                [
                    realpath(Yii::getAlias('@app') . '/yii'),
                    'extension/dummy',
                    'Extension already activated!',
                ],
                ExtensionsManager::EXTENSION_DUMMY_DEFERRED_GROUP
            );
            $chain->addTask($dummyTask);
        }
    }

    /**
     * Adds uninstall task into ReportingChain
     *
     * @param $extension
     * @param ReportingChain $chain
     */
    private static function uninstall($extension, ReportingChain $chain)
    {
        $module = ExtensionsManager::module();
        if (true === $module->extensionIsCore($extension['composer_name'])) {
            $dummyTask = ExtensionDataHelper::buildTask(
                [
                    realpath(Yii::getAlias('@app') . '/yii'),
                    'extension/dummy',
                    '--no-interaction',
                    '-o',
                    'You are unable to uninstall core extensions!',
                ],
                ExtensionsManager::EXTENSION_DUMMY_DEFERRED_GROUP
            );
            $chain->addTask($dummyTask);
        } else {
            self::deactivate($extension, $chain);
            $uninstallTask = ExtensionDataHelper::buildTask(
                [
                    $module->composerPath,
                    'remove',
                    $extension['composer_name'],
                    '--no-ansi',
                    '--no-interaction',
                    "--working-dir={$module->getLocalExtensionsPath()}",
                    $module->verbose == 1 ? '-vvv' : '',
                ],
                ExtensionsManager::COMPOSER_UNINSTALL_DEFERRED_GROUP
            );
            $chain->addTask($uninstallTask);
        }
    }

    /**
     * Runs separated ReportingTask
     *
     * @param $command
     * @param $groupName
     * @return array
     * @throws ServerErrorHttpException
     */
    private static function runTask($command, $groupName)
    {
        $task = ExtensionDataHelper::buildTask($command, $groupName);
        if ($task->registerTask()) {
            DeferredHelper::runImmediateTask($task->model()->id);
            Yii::$app->response->format = Response::FORMAT_JSON;
            return [
                'queueItemId' => $task->model()->id,
            ];
        } else {
            throw new ServerErrorHttpException("Unable to start task");
        }
    }
}


<?php

/**
 * @file
 * TeamSpeak 3 PHP Framework
 *
 * $Id: Channel.php 9/26/2011 7:06:29 scp@orilla $
 *
 * 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 3 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, see <http://www.gnu.org/licenses/>.
 *
 * @package   TeamSpeak3
 * @version   1.1.8-beta
 * @author    Sven 'ScP' Paulsen
 * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved.
 */

namespace ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3\Node;

/**
 * @class TeamSpeak3_Node_Channel
 * @brief Class describing a TeamSpeak 3 channel and all it's parameters.
 */
class Channel extends AbstractNode
{
  /**
   * The TeamSpeak3_Node_Channel constructor.
   *
   * @param  Server $server
   * @param  array  $info
   * @param  string $index
   * @throws \ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3\Adapter\ServerQuery\Exception
   * @return Channel
   */
  public function __construct(Server $server, array $info, $index = "cid")
  {
    $this->parent = $server;
    $this->nodeInfo = $info;

    if(!array_key_exists($index, $this->nodeInfo))
    {
      throw new \ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3\Adapter\ServerQuery\Exception("invalid channelID", 0x300);
    }

    $this->nodeId = $this->nodeInfo[$index];
  }

  /**
   * Returns an array filled with TeamSpeak3_Node_Channel objects.
   *
   * @param  array $filter
   * @return array
   */
  public function subChannelList(array $filter = array())
  {
    $channels = array();

    foreach($this->getParent()->channelList() as $channel)
    {
      if($channel["pid"] == $this->getId())
      {
        $channels[$channel->getId()] = $channel;
      }
    }

    return $this->filterList($channels, $filter);
  }

  /**
   * Returns the TeamSpeak3_Node_Channel object matching the given ID.
   *
   * @param  integer $cid
   * @throws \ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3\Adapter\ServerQuery\Exception
   * @return Channel
   */
  public function subChannelGetById($cid)
  {
    if(!array_key_exists((string) $cid, $this->subChannelList()))
    {
      throw new \ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3\Adapter\ServerQuery\Exception("invalid channelID", 0x300);
    }

    return $this->channelList[(string) $cid];
  }

  /**
   * Returns the TeamSpeak3_Node_Channel object matching the given name.
   *
   * @param  integer $name
   * @throws \ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3\Adapter\ServerQuery\Exception
   * @return Channel
   */
  public function subChannelGetByName($name)
  {
    foreach($this->subChannelList() as $channel)
    {
      if($channel["channel_name"] == $name) return $channel;
    }

    throw new \ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3\Adapter\ServerQuery\Exception("invalid channelID", 0x300);
  }

  /**
   * Returns an array filled with TeamSpeak3_Node_Client objects.
   *
   * @param  array $filter
   * @return array
   */
  public function clientList(array $filter = array())
  {
    $clients = array();

    foreach($this->getParent()->clientList() as $client)
    {
      if($client["cid"] == $this->getId())
      {
        $clients[$client->getId()] = $client;
      }
    }

    return $this->filterList($clients, $filter);
  }

  /**
   * Returns the TeamSpeak3_Node_Client object matching the given ID.
   *
   * @param  integer $clid
   * @throws \ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3\Adapter\ServerQuery\Exception
   * @return TeamSpeak3_Node_Client
   */
  public function clientGetById($clid)
  {
    if(!array_key_exists($clid, $this->clientList()))
    {
      throw new \ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3\Adapter\ServerQuery\Exception("invalid clientID", 0x200);
    }

    return $this->clientList[intval($clid)];
  }

  /**
   * Returns the TeamSpeak3_Node_Client object matching the given name.
   *
   * @param  integer $name
   * @throws \ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3\Adapter\ServerQuery\Exception
   * @return TeamSpeak3_Node_Client
   */
  public function clientGetByName($name)
  {
    foreach($this->clientList() as $client)
    {
      if($client["client_nickname"] == $name) return $client;
    }

    throw new \ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3\Adapter\ServerQuery\Exception("invalid clientID", 0x200);
  }

  /**
   * Returns a list of permissions defined for a client in the channel.
   *
   * @param  integer $cldbid
   * @param  boolean $permsid
   * @return void
   */
  public function clientPermList($cldbid, $permsid = FALSE)
  {
    return $this->getParent()->channelClientPermList($this->getId(), $cldbid, $permsid);
  }

  /**
   * Adds a set of specified permissions to a client in a specific channel. Multiple permissions can be added by
   * providing the two parameters of each permission.
   *
   * @param  integer $cldbid
   * @param  integer $permid
   * @param  integer $permvalue
   * @return void
   */
  public function clientPermAssign($cldbid, $permid, $permvalue)
  {
    return $this->getParent()->channelClientPermAssign($this->getId(), $cldbid, $permid, $permvalue);
  }

  /**
   * Alias for clientPermAssign().
   *
   * @deprecated
   */
  public function clientPermAssignByName($cldbid, $permname, $permvalue)
  {
    return $this->clientPermAssign($cldbid, $permname, $permvalue);
  }

  /**
   * Removes a set of specified permissions from a client in the channel. Multiple permissions can be removed at once.
   *
   * @param  integer $cldbid
   * @param  integer $permid
   * @return void
   */
  public function clientPermRemove($cldbid, $permid)
  {
    return $this->getParent()->channelClientPermRemove($this->getId(), $cldbid, $permid);
  }

  /**
   * Alias for clientPermRemove().
   *
   * @deprecated
   */
  public function clientPermRemoveByName($cldbid, $permname)
  {
    return $this->clientPermRemove($cldbid, $permname);
  }

  /**
   * Returns a list of permissions defined for the channel.
   *
   * @param  boolean $permsid
   * @return array
   */
  public function permList($permsid = FALSE)
  {
    return $this->getParent()->channelPermList($this->getId(), $permsid);
  }

  /**
   * Adds a set of specified permissions to the channel. Multiple permissions can be added by
   * providing the two parameters of each permission.
   *
   * @param  integer $permid
   * @param  integer $permvalue
   * @return void
   */
  public function permAssign($permid, $permvalue)
  {
    return $this->getParent()->channelPermAssign($this->getId(), $permid, $permvalue);
  }

  /**
   * Alias for permAssign().
   *
   * @deprecated
   */
  public function permAssignByName($permname, $permvalue)
  {
    return $this->permAssign($permname, $permvalue);
  }

  /**
   * Removes a set of specified permissions from the channel. Multiple permissions can be removed at once.
   *
   * @param  integer $permid
   * @return void
   */
  public function permRemove($permid)
  {
    return $this->getParent()->channelPermRemove($this->getId(), $permid);
  }

  /**
   * Alias for permRemove().
   *
   * @deprecated
   */
  public function permRemoveByName($permname)
  {
    return $this->permRemove($permname);
  }

  /**
   * Returns a list of files and directories stored in the channels file repository.
   *
   * @param  string  $cpw
   * @param  string  $path
   * @param  boolean $recursive
   * @return void
   */
  public function fileList($cpw = "", $path = "/", $recursive = FALSE)
  {
    return $this->getParent()->channelFileList($this->getId(), $cpw, $path, $recursive);
  }

  /**
   * Returns detailed information about the specified file stored in the channels file repository.
   *
   * @param  string  $cpw
   * @param  string  $name
   * @return array
   */
  public function fileInfo($cpw = "", $name = "/")
  {
    return $this->getParent()->channelFileInfo($this->getId(), $cpw, $name);
  }

  /**
   * Renames a file in the channels file repository. If the two parameters $tcid and $tcpw are specified, the file
   * will be moved into another channels file repository.
   *
   * @param  string  $cpw
   * @param  string  $oldname
   * @param  string  $newname
   * @param  integer $tcid
   * @param  string  $tcpw
   * @return void
   */
  public function fileRename($cpw = "", $oldname = "/", $newname = "/", $tcid = null, $tcpw = null)
  {
    return $this->getParent()->channelFileRename($this->getId(), $cpw, $oldname, $newname, $tcid, $tcpw);
  }

  /**
   * Deletes one or more files stored in the channels file repository.
   *
   * @param  string $cpw
   * @param  string $path
   * @return void
   */
  public function fileDelete($cpw = "", $name = "/")
  {
    return $this->getParent()->channelFileDelete($this->getId(), $cpw, $name);
  }

  /**
   * Creates new directory in a channels file repository.
   *
   * @param  string  $cpw
   * @param  string  $dirname
   * @return void
   */
  public function dirCreate($cpw = "", $dirname = "/")
  {
    return $this->getParent()->channelDirCreate($this->getId(), $cpw, $dirname);
  }

  /**
   * Returns the level of the channel.
   *
   * @return integer
   */
  public function getLevel()
  {
    return $this->getParent()->channelGetLevel($this->getId());
  }

  /**
   * Returns the pathway of the channel which can be used as a clients default channel.
   *
   * @return string
   */
  public function getPathway()
  {
    return $this->getParent()->channelGetPathway($this->getId());
  }

  /**
   * Returns the possible spacer type of the channel.
   *
   * @return integer
   */
  public function spacerGetType()
  {
    return $this->getParent()->channelSpacerGetType($this->getId());
  }

  /**
   * Returns the possible spacer alignment of the channel.
   *
   * @return integer
   */
  public function spacerGetAlign()
  {
    return $this->getParent()->channelSpacerGetAlign($this->getId());
  }

  /**
   * Returns TRUE if the channel is a spacer.
   *
   * @return boolean
   */
  public function isSpacer()
  {
    return $this->getParent()->channelIsSpacer($this);
  }

  /**
   * Downloads and returns the channels icon file content.
   *
   * @return TeamSpeak3_Helper_String
   */
  public function iconDownload()
  {
    if($this->iconIsLocal("channel_icon_id") || $this["channel_icon_id"] == 0) return;

    $download = $this->getParent()->transferInitDownload(rand(0x0000, 0xFFFF), 0, $this->iconGetName("channel_icon_id"));
    $transfer = \ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3\TeamSpeak3::factory("filetransfer://" . $download["host"] . ":" . $download["port"]);

    return $transfer->download($download["ftkey"], $download["size"]);
  }

  /**
   * Changes the channel configuration using given properties.
   *
   * @param  array $properties
   * @return void
   */
  public function modify(array $properties)
  {
    $properties["cid"] = $this->getId();

    $this->execute("channeledit", $properties);
    $this->resetNodeInfo();
  }

  /**
   * Sends a text message to all clients in the channel.
   *
   * @param  string $msg
   * @param  string $cpw
   * @return void
   */
  public function message($msg, $cpw = null)
  {
    if($this->getId() != $this->getParent()->whoamiGet("client_channel_id"))
    {
      $this->getParent()->clientMove($this->getParent()->whoamiGet("client_id"), $this->getId(), $cpw);
    }

    $this->execute("sendtextmessage", array("msg" => $msg, "target" => $this->getId(), "targetmode" => \ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3\TeamSpeak3::TEXTMSG_CHANNEL));
  }

  /**
   * Deletes the channel.
   *
   * @param  boolean $force
   * @return void
   */
  public function delete($force = FALSE)
  {
    $this->getParent()->channelDelete($this->getId(), $force);

    unset($this);
  }

  /**
   * Moves the channel to the parent channel specified with $pid.
   *
   * @param  integer $pid
   * @param  integer $order
   * @return void
   */
  public function move($pid, $order = null)
  {
    $this->getParent()->channelMove($this->getId(), $pid, $order);
  }

  /**
   * @ignore
   */
  protected function fetchNodeList()
  {
    $this->nodeList = array();

    if($this->getParent()->getLoadClientlistFirst())
    {
      foreach($this->clientList() as $client)
      {
        if($client["cid"] == $this->getId())
        {
          $this->nodeList[] = $client;
        }
      }

      foreach($this->subChannelList() as $channel)
      {
        if($channel["pid"] == $this->getId())
        {
          $this->nodeList[] = $channel;
        }
      }
    }
    else
    {
      foreach($this->subChannelList() as $channel)
      {
        if($channel["pid"] == $this->getId())
        {
          $this->nodeList[] = $channel;
        }
      }

      foreach($this->clientList() as $client)
      {
        if($client["cid"] == $this->getId())
        {
          $this->nodeList[] = $client;
        }
      }
    }
  }

  /**
   * @ignore
   */
  protected function fetchNodeInfo()
  {
    $this->nodeInfo = array_merge($this->nodeInfo, $this->execute("channelinfo", array("cid" => $this->getId()))->toList());
  }

  /**
   * Returns a unique identifier for the node which can be used as a HTML property.
   *
   * @return string
   */
  public function getUniqueId()
  {
    return $this->getParent()->getUniqueId() . "_ch" . $this->getId();
  }

  /**
   * Returns the name of a possible icon to display the node object.
   *
   * @return string
   */
  public function getIcon()
  {
    if($this["channel_maxclients"] != -1 && $this["channel_maxclients"] <= $this["total_clients"])
    {
      return "channel_full";
    }
    elseif($this["channel_flag_password"])
    {
      return "channel_pass";
    }
    else
    {
      return "channel_open";
    }
  }

  /**
   * Returns a symbol representing the node.
   *
   * @return string
   */
  public function getSymbol()
  {
    return "#";
  }

  /**
   * Returns a string representation of this node.
   *
   * @return string
   */
  public function __toString()
  {
    return (string) $this["channel_name"];
  }
}


<?php namespace Gears\Arrays\Conversions\To;
////////////////////////////////////////////////////////////////////////////////
// __________ __             ________                   __________
// \______   \  |__ ______  /  _____/  ____ _____ ______\______   \ _______  ___
//  |     ___/  |  \\____ \/   \  ____/ __ \\__  \\_  __ \    |  _//  _ \  \/  /
//  |    |   |   Y  \  |_> >    \_\  \  ___/ / __ \|  | \/    |   (  <_> >    <
//  |____|   |___|  /   __/ \______  /\___  >____  /__|  |______  /\____/__/\_ \
//                \/|__|           \/     \/     \/             \/            \/
// -----------------------------------------------------------------------------
//          Designed and Developed by Brad Jones <brad @="bjc.id.au" />
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////

use \Gears\Arrays\Conversions\Template;

class Csv extends Template
{
	/**
	 * Property: delimiter
	 * =========================================================================
	 * This is the delimiter or seperator that is used in the CSV.
	 * For example you could actually turn this into a TSV Driver by using "\t"
	 *
	 * Defaults to ,
	 */
	protected $delimiter = ',';

	/**
	 * Property: enclosure
	 * =========================================================================
	 * This is the character that is used to enclose or surround the values.
	 * Eg:
	 * 	row1, abc, 123			(WITHOUT ENCLOSURE)
	 * 	"row2", "abc", "123"	(WITH ENCLOSURE)
	 *
	 * Defaults to "
	 */
	protected $enclosure = '"';

	/**
	 * Property: memory
	 * =========================================================================
	 * This is the amount of memory that we will take up to create a
	 * file pointer to a temporay place in main memory.
	 *
	 * Defaults to 5MB
	 */
	protected $memory = 5;

	/**
	 * Property: headings
	 * =========================================================================
	 * Do we treat the first row in the CSV as headings for our array.
	 * Or do we just output a number indexed array.
	 *
	 * Defaults to true
	 */
	protected $headings = true;

	/*
	 * Method: Convert
	 * =========================================================================
	 * This will do the actual converting
	 *
	 * Parameters:
	 * -------------------------------------------------------------------------
	 * $data - An array to convert to CSV
	 *
	 * Returns:
	 * -------------------------------------------------------------------------
	 * csv
	 */
	public function Convert($data)
	{
		// Create a file pointer
		$fp = fopen('php://temp/maxmemory:'.$this->memory*(1024*1024), 'r+');

		// Loop through each line
		foreach ($data as $line)
		{
			fputcsv($fp, $line, $this->delimiter, $this->enclosure);
		}

		// Get the CSV as a String
		rewind($fp); $csv = stream_get_contents($fp); fclose($fp);

		// Add the headings
		if($this->headings == true)
		{
			// Create the headings line
			$headings = '';
			foreach ($data[0] as $key => $value)
			{
				$headings .= $key.',';
			}

			// Remove the last comma
			$headings = substr($headings, 0, -1);

			// Append the headings to the csv
			$csv = $headings."\n".$csv;
		}

		// Return the CSV
		return $csv;
	}
}


<?php

namespace Encore\Wx\Element\Traits;

use wxPoint;

trait Positionable
{
    /**
     * Create a new wxPoint object from the x/y position
     *
     * @return wxPoint
     */
    protected function getPosition()
    {
        if ($this->x and $this->y) {
            return new wxPoint($this->x, $this->y);
        }

        return wxDefaultPosition;
    }
}


<?php

namespace QuanKim\PhpJwt;
use Cake\Core\Configure;
use Cake\ORM\TableRegistry;
use \DomainException;
use \InvalidArgumentException;
use \UnexpectedValueException;
use \DateTime;
use Cake\Utility\Security;
/**
 * JSON Web Token implementation, based on this spec:
 * http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-06
 *
 * PHP version 5
 *
 * @category Authentication
 * @package  Authentication_JWT
 * @author   Neuman Vong <neuman@twilio.com>
 * @author   Anant Narayanan <anant@php.net>
 * @license  http://opensource.org/licenses/BSD-3-Clause 3-clause BSD
 * @link     https://github.com/quankim
 */
class JWT
{

    /**
     * When checking nbf, iat or expiration times,
     * we want to provide some extra leeway time to
     * account for clock skew.
     */
    public static $leeway = 0;

    public static $supported_algs = array(
        'HS256' => array('hash_hmac', 'SHA256'),
        'HS512' => array('hash_hmac', 'SHA512'),
        'HS384' => array('hash_hmac', 'SHA384'),
        'RS256' => array('openssl', 'SHA256'),
    );

    /**
     * Decodes a JWT string into a PHP object.
     *
     * @param string            $jwt            The JWT
     * @param string|array|null $key            The key, or map of keys.
     *                                          If the algorithm used is asymmetric, this is the public key
     * @param array             $allowed_algs   List of supported verification algorithms
     *                                          Supported algorithms are 'HS256', 'HS384', 'HS512' and 'RS256'
     *
     * @return object The JWT's payload as a PHP object
     *
     * @throws DomainException              Algorithm was not provided
     * @throws UnexpectedValueException     Provided JWT was invalid
     * @throws SignatureInvalidException    Provided JWT was invalid because the signature verification failed
     * @throws BeforeValidException         Provided JWT is trying to be used before it's eligible as defined by 'nbf'
     * @throws BeforeValidException         Provided JWT is trying to be used before it's been created as defined by 'iat'
     * @throws ExpiredException             Provided JWT has since expired, as defined by the 'exp' claim
     *
     * @uses jsonDecode
     * @uses urlsafeB64Decode
     */
    public static function decode($jwt, $key, $allowed_algs = array())
    {
        if (empty($key)) {
            throw new InvalidArgumentException('Key may not be empty');
        }
        $tks = explode('.', $jwt);
        if (count($tks) != 3) {
            throw new UnexpectedValueException('Wrong number of segments');
        }
        list($headb64, $bodyb64, $cryptob64) = $tks;
        if (null === ($header = JWT::jsonDecode(JWT::urlsafeB64Decode($headb64)))) {
            throw new UnexpectedValueException('Invalid header encoding');
        }
        if (null === $payload = JWT::jsonDecode(JWT::urlsafeB64Decode($bodyb64))) {
            throw new UnexpectedValueException('Invalid claims encoding');
        }
        $sig = JWT::urlsafeB64Decode($cryptob64);

        if (empty($header->alg)) {
            throw new DomainException('Empty algorithm');
        }
        if (empty(self::$supported_algs[$header->alg])) {
            throw new DomainException('Algorithm not supported');
        }
        if (!is_array($allowed_algs) || !in_array($header->alg, $allowed_algs)) {
            throw new DomainException('Algorithm not allowed');
        }
        if (is_array($key) || $key instanceof \ArrayAccess) {
            if (isset($header->kid)) {
                $key = $key[$header->kid];
            } else {
                throw new DomainException('"kid" empty, unable to lookup correct key');
            }
        }

        // Check the signature
        if (!JWT::verify("$headb64.$bodyb64", $sig, $key, $header->alg)) {
            throw new SignatureInvalidException('Signature verification failed');
        }

        // Check if the nbf if it is defined. This is the time that the
        // token can actually be used. If it's not yet that time, abort.
        if (isset($payload->nbf) && $payload->nbf > (time() + self::$leeway)) {
            throw new BeforeValidException(
                'Cannot handle token prior to ' . date(DateTime::ISO8601, $payload->nbf)
            );
        }

        // Check that this token has been created before 'now'. This prevents
        // using tokens that have been created for later use (and haven't
        // correctly used the nbf claim).
        if (isset($payload->iat) && $payload->iat > (time() + self::$leeway)) {
            throw new BeforeValidException(
                'Cannot handle token prior to ' . date(DateTime::ISO8601, $payload->iat)
            );
        }
        // Check if refresh token return access t
        if (isset($payload->ref)) {
            header('Content-Type:application/json');
            $table = TableRegistry::get('AuthToken');
            $authToken = $table->find('all')->where(['user_id'=>$payload->sub,'refresh_token'=>$jwt])->first();
            if ($authToken) {
                $expire =  (!is_null(Configure::read('AuthToken.expire'))) ? Configure::read('AuthToken.expire') : 3600;
                $access_token = JWT::encode([
                    'sub' => $authToken['user_id'],
                    'exp' =>  time() + $expire
                ],Security::salt());
                $refresh_token = JWT::encode([
                    'sub' => $authToken['user_id'],
                    'ref'=>time()
                ],Security::salt());
                $authToken->access_token = $access_token;
                $authToken->refresh_token = $refresh_token;
                $table->save($authToken);
                echo json_encode([
                    'success'=>true,
                    'data'=>[
                        'access_token'=>$access_token,
                        'refresh_token'=>$refresh_token
                    ]
                ]);
            } else {
                echo json_encode([
                    'success'=>false,
                    'refresh_token_expired'=>true
                ]);
            }
            exit();
        }
        // Check if this token has expired.
        if (isset($payload->exp) && (time() - self::$leeway) >= $payload->exp) {
            //throw new ExpiredException('Expired token');
            header('Content-Type:application/json');
            echo json_encode([
                'success'=>false,
                'access_token_expired'=>true
            ]);
            exit();
        }

        return $payload;
    }

    /**
     * Converts and signs a PHP object or array into a JWT string.
     *
     * @param object|array  $payload    PHP object or array
     * @param string        $key        The secret key.
     *                                  If the algorithm used is asymmetric, this is the private key
     * @param string        $alg        The signing algorithm.
     *                                  Supported algorithms are 'HS256', 'HS384', 'HS512' and 'RS256'
     * @param array         $head       An array with header elements to attach
     *
     * @return string A signed JWT
     *
     * @uses jsonEncode
     * @uses urlsafeB64Encode
     */
    public static function encode($payload, $key, $alg = 'HS256', $keyId = null, $head = null)
    {
        $header = array('typ' => 'JWT', 'alg' => $alg);
        if ($keyId !== null) {
            $header['kid'] = $keyId;
        }
        if ( isset($head) && is_array($head) ) {
            $header = array_merge($head, $header);
        }
        $segments = array();
        $segments[] = JWT::urlsafeB64Encode(JWT::jsonEncode($header));
        $segments[] = JWT::urlsafeB64Encode(JWT::jsonEncode($payload));
        $signing_input = implode('.', $segments);

        $signature = JWT::sign($signing_input, $key, $alg);
        $segments[] = JWT::urlsafeB64Encode($signature);

        return implode('.', $segments);
    }

    /**
     * Sign a string with a given key and algorithm.
     *
     * @param string            $msg    The message to sign
     * @param string|resource   $key    The secret key
     * @param string            $alg    The signing algorithm.
     *                                  Supported algorithms are 'HS256', 'HS384', 'HS512' and 'RS256'
     *
     * @return string An encrypted message
     *
     * @throws DomainException Unsupported algorithm was specified
     */
    public static function sign($msg, $key, $alg = 'HS256')
    {
        if (empty(self::$supported_algs[$alg])) {
            throw new DomainException('Algorithm not supported');
        }
        list($function, $algorithm) = self::$supported_algs[$alg];
        switch($function) {
            case 'hash_hmac':
                return hash_hmac($algorithm, $msg, $key, true);
            case 'openssl':
                $signature = '';
                $success = openssl_sign($msg, $signature, $key, $algorithm);
                if (!$success) {
                    throw new DomainException("OpenSSL unable to sign data");
                } else {
                    return $signature;
                }
        }
    }

    /**
     * Verify a signature with the message, key and method. Not all methods
     * are symmetric, so we must have a separate verify and sign method.
     *
     * @param string            $msg        The original message (header and body)
     * @param string            $signature  The original signature
     * @param string|resource   $key        For HS*, a string key works. for RS*, must be a resource of an openssl public key
     * @param string            $alg        The algorithm
     *
     * @return bool
     *
     * @throws DomainException Invalid Algorithm or OpenSSL failure
     */
    private static function verify($msg, $signature, $key, $alg)
    {
        if (empty(self::$supported_algs[$alg])) {
            throw new DomainException('Algorithm not supported');
        }

        list($function, $algorithm) = self::$supported_algs[$alg];
        switch($function) {
            case 'openssl':
                $success = openssl_verify($msg, $signature, $key, $algorithm);
                if (!$success) {
                    throw new DomainException("OpenSSL unable to verify data: " . openssl_error_string());
                } else {
                    return $signature;
                }
            case 'hash_hmac':
            default:
                $hash = hash_hmac($algorithm, $msg, $key, true);
                if (function_exists('hash_equals')) {
                    return hash_equals($signature, $hash);
                }
                $len = min(self::safeStrlen($signature), self::safeStrlen($hash));

                $status = 0;
                for ($i = 0; $i < $len; $i++) {
                    $status |= (ord($signature[$i]) ^ ord($hash[$i]));
                }
                $status |= (self::safeStrlen($signature) ^ self::safeStrlen($hash));

                return ($status === 0);
        }
    }

    /**
     * Decode a JSON string into a PHP object.
     *
     * @param string $input JSON string
     *
     * @return object Object representation of JSON string
     *
     * @throws DomainException Provided string was invalid JSON
     */
    public static function jsonDecode($input)
    {
        if (version_compare(PHP_VERSION, '5.4.0', '>=') && !(defined('JSON_C_VERSION') && PHP_INT_SIZE > 4)) {
            /** In PHP >=5.4.0, json_decode() accepts an options parameter, that allows you
             * to specify that large ints (like Steam Transaction IDs) should be treated as
             * strings, rather than the PHP default behaviour of converting them to floats.
             */
            $obj = json_decode($input, false, 512, JSON_BIGINT_AS_STRING);
        } else {
            /** Not all servers will support that, however, so for older versions we must
             * manually detect large ints in the JSON string and quote them (thus converting
             *them to strings) before decoding, hence the preg_replace() call.
             */
            $max_int_length = strlen((string) PHP_INT_MAX) - 1;
            $json_without_bigints = preg_replace('/:\s*(-?\d{'.$max_int_length.',})/', ': "$1"', $input);
            $obj = json_decode($json_without_bigints);
        }

        if (function_exists('json_last_error') && $errno = json_last_error()) {
            JWT::handleJsonError($errno);
        } elseif ($obj === null && $input !== 'null') {
            throw new DomainException('Null result with non-null input');
        }
        return $obj;
    }

    /**
     * Encode a PHP object into a JSON string.
     *
     * @param object|array $input A PHP object or array
     *
     * @return string JSON representation of the PHP object or array
     *
     * @throws DomainException Provided object could not be encoded to valid JSON
     */
    public static function jsonEncode($input)
    {
        $json = json_encode($input);
        if (function_exists('json_last_error') && $errno = json_last_error()) {
            JWT::handleJsonError($errno);
        } elseif ($json === 'null' && $input !== null) {
            throw new DomainException('Null result with non-null input');
        }
        return $json;
    }

    /**
     * Decode a string with URL-safe Base64.
     *
     * @param string $input A Base64 encoded string
     *
     * @return string A decoded string
     */
    public static function urlsafeB64Decode($input)
    {
        $remainder = strlen($input) % 4;
        if ($remainder) {
            $padlen = 4 - $remainder;
            $input .= str_repeat('=', $padlen);
        }
        return base64_decode(strtr($input, '-_', '+/'));
    }

    /**
     * Encode a string with URL-safe Base64.
     *
     * @param string $input The string you want encoded
     *
     * @return string The base64 encode of what you passed in
     */
    public static function urlsafeB64Encode($input)
    {
        return str_replace('=', '', strtr(base64_encode($input), '+/', '-_'));
    }

    /**
     * Helper method to create a JSON error.
     *
     * @param int $errno An error number from json_last_error()
     *
     * @return void
     */
    private static function handleJsonError($errno)
    {
        $messages = array(
            JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
            JSON_ERROR_CTRL_CHAR => 'Unexpected control character found',
            JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON'
        );
        throw new DomainException(
            isset($messages[$errno])
            ? $messages[$errno]
            : 'Unknown JSON error: ' . $errno
        );
    }

    /**
     * Get the number of bytes in cryptographic strings.
     *
     * @param string
     *
     * @return int
     */
    private static function safeStrlen($str)
    {
        if (function_exists('mb_strlen')) {
            return mb_strlen($str, '8bit');
        }
        return strlen($str);
    }
}


<?php

namespace DevGroup\ExtensionsManager\helpers;

use Yii;
use yii\base\Component;
use yii\base\InvalidConfigException;
use yii\helpers\ArrayHelper;
use yii\helpers\VarDumper;

/**
 * Writer for application configs
 * @package app\modules\config\helpers
 */
class ApplicationConfigWriter extends Component
{
    /**
     * @var string Filename to read-write for
     */
    public $filename = null;
    /**
     * @var array Configuration array that will be written to filesystem
     */
    public $configuration = [];
    /**
     * @var string Code to append
     */
    public $append = '';

    /**
     * @inheritdoc
     * @throws InvalidConfigException
     */
    public function init()
    {
        parent::init();
        if ($this->filename === null) {
            throw new InvalidConfigException(
                Yii::t(
                    'extensions-manager',
                    'Filename should be set for ApplicationConfigWriter'
                )
            );
        }
        $this->filename = Yii::getAlias($this->filename);
    }

    /**
     * Add values to current configuration array with merging.
     * @param array $values Values to merge from
     */
    public function addValues($values)
    {
        $this->configuration = ArrayHelper::merge($this->configuration, $values);
    }
    /**
     * Writes all configuration to application configuration file
     * @return bool result, true if success
     */
    public function commit()
    {
        $data = <<<PHP
<?php
/*
 * ! WARNING !
 *
 * This file is auto-generated.
 * Please don't modify it by-hand or all your changes can be lost.
 */
{$this->append}
return
PHP;
        $data .= VarDumper::export($this->configuration);
        $data .= ";\n\n";

        $result = file_put_contents($this->filename, $data, LOCK_EX) !== false;
        if ($result) {
            if (function_exists('opcache_invalidate')) {
                opcache_invalidate($this->filename, true);
            }
            if (function_exists('apc_delete_file')) {
                @apc_delete_file($this->filename);
            }
        }
        return $result;
    }
}


<?php

namespace DevGroup\ExtensionsManager;

use DevGroup\DeferredTasks\events\DeferredQueueEvent;
use DevGroup\ExtensionsManager\components\ComposerInstalledSet;
use DevGroup\ExtensionsManager\helpers\ExtensionDataHelper;
use DevGroup\ExtensionsManager\models\Extension;
use Yii;
use yii\base\Application;
use yii\base\BootstrapInterface;
use DevGroup\DeferredTasks\commands\DeferredController;
use DevGroup\ExtensionsManager\commands\ExtensionController;
use DevGroup\ExtensionsManager\handlers\DeferredQueueCompleteHandler;

class Bootstrap implements BootstrapInterface
{
    /**
     * Bootstrap method to be called during application bootstrap stage.
     *
     * @param Application $app the application currently running
     */
    public function bootstrap($app)
    {
        $app->i18n->translations['extensions-manager'] = [
            'class' => 'yii\i18n\PhpMessageSource',
            'basePath' => __DIR__ . DIRECTORY_SEPARATOR . 'messages',
        ];
        DeferredQueueEvent::on(
            DeferredController::className(),
            DeferredController::EVENT_DEFERRED_QUEUE_COMPLETE,
            [DeferredQueueCompleteHandler::className(), 'handleEvent']
        );
        if ($app instanceof \yii\console\Application) {
            $app->controllerMap['extension'] = ExtensionController::className();
            $app->on(Application::EVENT_BEFORE_ACTION, function () {
                $module = ExtensionsManager::module();
                if ($module->autoDiscoverMigrations === true) {
                    if (isset(Yii::$app->params['yii.migrations']) === false) {
                        Yii::$app->params['yii.migrations'] = [];
                    }
                    /** @var array $extensions */
                    $extensions = $module->getExtensions();
                    foreach ($extensions as $name => $ext) {
                        if ($ext['composer_type'] === Extension::TYPE_DOTPLANT
                            && $module->discoverDotPlantMigrations === false
                        ) {
                            continue;
                        }
                        $extData = ComposerInstalledSet::get()->getInstalled($ext['composer_name']);
                        $packageMigrations = ExtensionDataHelper::getInstalledExtraData(
                            $extData,
                            'migrationPath',
                            true
                        );
                        $packagePath = '@vendor/' . $ext['composer_name'];
                        foreach ($packageMigrations as $migrationPath) {
                            Yii::$app->params['yii.migrations'][] = "$packagePath/$migrationPath";
                        }
                    }
                }
            });
        }
    }
}


<?php

/**
 * @file
 * TeamSpeak 3 PHP Framework
 *
 * $Id: Channelgroup.php 9/26/2011 7:06:29 scp@orilla $
 *
 * 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 3 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, see <http://www.gnu.org/licenses/>.
 *
 * @package   TeamSpeak3
 * @version   1.1.8-beta
 * @author    Sven 'ScP' Paulsen
 * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved.
 */

namespace ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3\Node;

/**
 * @class TeamSpeak3_Node_Channelgroup
 * @brief Class describing a TeamSpeak 3 channel group and all it's parameters.
 */
class Channelgroup extends AbstractNode
{
  /**
   * The TeamSpeak3_Node_Channelgroup constructor.
   *
   * @param  Server $server
   * @param  array  $info
   * @param  string $index
   * @throws \ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3\Adapter\ServerQuery\Exception
   * @return Channelgroup
   */
  public function __construct(Server $server, array $info, $index = "cgid")
  {
    $this->parent = $server;
    $this->nodeInfo = $info;

    if(!array_key_exists($index, $this->nodeInfo))
    {
      throw new \ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3\Adapter\ServerQuery\Exception("invalid groupID", 0xA00);
    }

    $this->nodeId = $this->nodeInfo[$index];
  }

  /**
   * Renames the channel group specified.
   *
   * @param  string $name
   * @return void
   */
  public function rename($name)
  {
    return $this->getParent()->channelGroupRename($this->getId(), $name);
  }

  /**
   * Deletes the channel group. If $force is set to TRUE, the channel group will be
   * deleted even if there are clients within.
   *
   * @param  boolean $force
   * @return void
   */
  public function delete($force = FALSE)
  {
    $this->getParent()->channelGroupDelete($this->getId(), $force);

    unset($this);
  }

  /**
   * Creates a copy of the channel group and returns the new groups ID.
   *
   * @param  string  $name
   * @param  integer $tcgid
   * @param  integer $type
   * @return integer
   */
  public function copy($name = null, $tcgid = 0, $type = \ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3\TeamSpeak3::GROUP_DBTYPE_REGULAR)
  {
    return $this->getParent()->channelGroupCopy($this->getId(), $name, $tcgid, $type);
  }

  /**
   * Returns a list of permissions assigned to the channel group.
   *
   * @param  boolean $permsid
   * @return array
   */
  public function permList($permsid = FALSE)
  {
    return $this->getParent()->channelGroupPermList($this->getId(), $permsid);
  }

  /**
   * Adds a set of specified permissions to the channel group. Multiple permissions
   * can be added by providing the two parameters of each permission in separate arrays.
   *
   * @param  integer $permid
   * @param  integer $permvalue
   * @return void
   */
  public function permAssign($permid, $permvalue)
  {
    return $this->getParent()->channelGroupPermAssign($this->getId(), $permid, $permvalue);
  }

  /**
   * Alias for permAssign().
   *
   * @deprecated
   */
  public function permAssignByName($permname, $permvalue)
  {
    return $this->permAssign($permname, $permvalue);
  }

  /**
   * Removes a set of specified permissions from the channel group. Multiple
   * permissions can be removed at once.
   *
   * @param  integer $permid
   * @return void
   */
  public function permRemove($permid)
  {
    return $this->getParent()->channelGroupPermRemove($this->getId(), $permid);
  }

  /**
   * Alias for permAssign().
   *
   * @deprecated
   */
  public function permRemoveByName($permname)
  {
    return $this->permRemove($permname);
  }

  /**
   * Returns a list of clients assigned to the server group specified.
   *
   * @return array
   */
  public function clientList()
  {
    return $this->getParent()->channelGroupClientList($this->getId());
  }

  /**
   * Alias for privilegeKeyCreate().
   *
   * @deprecated
   */
  public function tokenCreate($cid, $description = null, $customset = null)
  {
    return $this->privilegeKeyCreate($cid, $description, $customset);
  }

  /**
   * Creates a new privilege key (token) for the channel group and returns the key.
   *
   * @param  integer $cid
   * @param  string  $description
   * @param  string  $customset
   * @return TeamSpeak3_Helper_String
   */
  public function privilegeKeyCreate($cid, $description = null, $customset = null)
  {
    return $this->getParent()->privilegeKeyCreate(\ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3\TeamSpeak3::TOKEN_CHANNELGROUP, $this->getId(), $cid, $description, $customset);
  }

  /**
   * Sends a text message to all clients residing in the channel group on the virtual server.
   *
   * @param  string $msg
   * @return void
   */
  public function message($msg)
  {
    foreach($this as $client)
    {
      try
      {
        $this->execute("sendtextmessage", array("msg" => $msg, "target" => $client, "targetmode" => \ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3\TeamSpeak3::TEXTMSG_CLIENT));
      }
      catch(\ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3\Adapter\ServerQuery\Exception $e)
      {
        /* ERROR_client_invalid_id */
        if($e->getCode() != 0x0200) throw $e;
      }
    }
  }

  /**
   * Downloads and returns the channel groups icon file content.
   *
   * @return TeamSpeak3_Helper_String
   */
  public function iconDownload()
  {
    if($this->iconIsLocal("iconid") || $this["iconid"] == 0) return;

    $download = $this->getParent()->transferInitDownload(rand(0x0000, 0xFFFF), 0, $this->iconGetName("iconid"));
    $transfer = \ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3\TeamSpeak3::factory("filetransfer://" . $download["host"] . ":" . $download["port"]);

    return $transfer->download($download["ftkey"], $download["size"]);
  }

  /**
   * @ignore
   */
  protected function fetchNodeList()
  {
    $this->nodeList = array();

    foreach($this->getParent()->clientList() as $client)
    {
      if($client["client_channel_group_id"] == $this->getId())
      {
        $this->nodeList[] = $client;
      }
    }
  }

  /**
   * Returns a unique identifier for the node which can be used as a HTML property.
   *
   * @return string
   */
  public function getUniqueId()
  {
    return $this->getParent()->getUniqueId() . "_cg" . $this->getId();
  }

  /**
   * Returns the name of a possible icon to display the node object.
   *
   * @return string
   */
  public function getIcon()
  {
    return "group_channel";
  }

  /**
   * Returns a symbol representing the node.
   *
   * @return string
   */
  public function getSymbol()
  {
    return "%";
  }

  /**
   * Returns a string representation of this node.
   *
   * @return string
   */
  public function __toString()
  {
    return (string) $this["name"];
  }
}


<?php

namespace Karika\CoreBundle\Controller\Api;

use FOS\RestBundle\Controller\FOSRestController;
use Karika\CoreBundle\Entity\Manager\ApiEntityManager;
use Karika\CoreBundle\Form\ProductType;

use FOS\RestBundle\Controller\Annotations\QueryParam;
use FOS\RestBundle\Controller\Annotations\RouteResource;
use FOS\RestBundle\Controller\Annotations\View;
use FOS\RestBundle\Request\ParamFetcherInterface;
use FOS\RestBundle\View\View as FOSView;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Form\Form;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;

/**
 * Base controller for API.
 */
abstract class ApiController extends FOSRestController
{
    /**
     * @var string Form class name for this controller
     */
    protected $formClassName;

    /**
     * Get Entity class name for this controller
     *
     * @return string
     */
    abstract protected function entityClassName(): string;

    /**
     * Get Form class name for this controller
     *
     * Override this method if necessary
     *
     * @return string
     */
    protected function formClassName(): string
    {
        if ($this->formClassName)
        {
            return $this->formClassName;
        }

        $entityClassName = $this->entityClassName();
        $this->formClassName = substr(str_replace('/Form/', '/Entity/', $entityClassName), 0, -4);

        return $this->formClassName;
    }

    /**
     * Get a Product entity
     *
     * @ApiDoc
     *
     * @View(serializerEnableMaxDepthChecks=true)
     *
     * @param int $id
     *
     * @return FOSView|object
     *
     */
    public function getAction(int $id)
    {
        try {
            $em = $this->getDoctrine()->getManager();
            $entity = $em->getRepository($this->entityClassName())->find($id);
            if ($entity) {
                return $entity;
            }
            return FOSView::create('Not Found', Response::HTTP_NO_CONTENT);
        } catch (\Exception $e) {
            return FOSView::create($e->getMessage(), Response::HTTP_INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * Get all Product entities.
     *
     * @ApiDoc
     *
     * @View(serializerEnableMaxDepthChecks=true)
     *
     * @param ParamFetcherInterface $paramFetcher
     *
     * @return array|FOSView
     *
     * @QueryParam(name="offset", requirements="\d+", nullable=true, description="Offset from which to start listing notes.")
     * @QueryParam(name="limit", requirements="\d+", default="20", description="How many notes to return.")
     * @QueryParam(name="order_by", nullable=true, map=true, description="Order by fields. Must be an array ie. &order_by[name]=ASC&order_by[description]=DESC")
     * @QueryParam(name="filters", nullable=true, map=true, description="Filter by fields. Must be an array ie. &filters[id]=3")
     */
    public function cgetAction(ParamFetcherInterface $paramFetcher)
    {
        try {
            $offset = $paramFetcher->get('offset');
            $limit = $paramFetcher->get('limit');
            $order_by = $paramFetcher->get('order_by');
            $filters = !is_null($paramFetcher->get('filters')) ? $paramFetcher->get('filters') : array();

            $em = $this->getDoctrine()->getManager();
            $entities = $em->getRepository($this->entityClassName())
                ->findBy($filters, $order_by, $limit, $offset);

            if ($entities) {
                return $entities;
            }

            return FOSView::create('Not Found', Response::HTTP_NO_CONTENT);
        } catch (\Exception $e) {
            return FOSView::create($e->getMessage(), Response::HTTP_INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * Create a Product entity.
     *
     * @ApiDoc
     *
     * @View(statusCode=201, serializerEnableMaxDepthChecks=true)
     *
     * @param Request $request
     *
     * @return object
     *
     */
    public function postAction(Request $request)
    {
        /**
         * @var $em ApiEntityManager
         */
        $em = $this->getDoctrine()->getManager();

        $data = json_decode($request->getContent(), true);
        $entity = $em->createEntity($this->entityClassName());

        $form = $this->createForm($this->formClassName(), $entity, [
            "method" => $request->getMethod(),
        ]);

        $form->submit($data);

        if ($form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $em->persist($entity);
            $em->flush();

            return $entity;
        }

        return FOSView::create([
            'errors' => $form->getErrors()
        ], Response::HTTP_INTERNAL_SERVER_ERROR);
    }

    /**
     * Update a Product entity.
     *
     * @ApiDoc
     *
     * @View(serializerEnableMaxDepthChecks=true)
     *
     * @param Request $request
     * @param int $id
     *
     * @return object
     */
    public function putAction(Request $request, int $id)
    {
        try {
            $em = $this->getDoctrine()->getManager();

            $entity = $em->getRepository($this->entityClassName())->find($id);

            $data = json_decode($request->getContent(), true);

            $request->setMethod('PATCH'); //Treat all PUTs as PATCH
            $form = $this->createForm($this->formClassName(), $entity, [
                "method" => $request->getMethod(),
            ]);

            $form->submit($data);

            if ($form->isValid()) {
                $em->flush();

                return $entity;
            }

            return FOSView::create(array('errors' => $form->getErrors()), Response::HTTP_INTERNAL_SERVER_ERROR);
        } catch (\Exception $e) {
            return FOSView::create($e->getMessage(), Response::HTTP_INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * Partial Update to a Product entity.
     *
     * @ApiDoc
     *
     * @View(serializerEnableMaxDepthChecks=true)
     *
     * @param Request $request
     * @param int $id
     *
     * @return object
     */
    public function patchAction(Request $request, int $id)
    {
        return $this->putAction($request, $id);
    }

    /**
     * Delete a Product entity.
     *
     * @ApiDoc
     *
     * @View(statusCode=204)
     *
     * @param Request $request
     * @param int $id
     *
     * @return null|FOSView
     */
    public function deleteAction(Request $request, int $id)
    {
        try {
            $em = $this->getDoctrine()->getManager();

            $entity = $em->getRepository($this->entityClassName())->find($id);
            $em->remove($entity);
            $em->flush();

            return null;
        } catch (\Exception $e) {
            return FOSView::create($e->getMessage(), Response::HTTP_INTERNAL_SERVER_ERROR);
        }
    }
}


<?php

namespace Schnittstabil\JsonDecodeFile;

use KHerGe\File\File;
use KHerGe\File\Exception\ResourceException;
use Seld\JsonLint\JsonParser;
use Seld\JsonLint\ParsingException;
use duncan3dc\Bom\Util as BomUtil;

/**
 * Read and decode JSON files.
 */
class JsonDecodeFile
{
    /**
     * Reads entire file into a string.
     *
     * @param string $path the file path
     *
     * @return string the read data
     *
     * @throws ResourceException
     */
    protected static function readFile($path)
    {
        // Workaround for https://github.com/kherge-php/file-manager/pull/2
        $error = null;
        set_error_handler(function ($severity, $message, $filename, $lineno) use (&$error) {
            $error = new \ErrorException($message, 0, $severity, $filename, $lineno);
        }, E_WARNING);

        try {
            $file = new File($path, 'r');
        } finally {
            restore_error_handler();
        }

        if ($error) {
            // @codeCoverageIgnoreStart
            throw new ResourceException(
                "The file \"$path\" could not be opened.",
                $error
            );
            // @codeCoverageIgnoreEnd
        }

        return $file->read();
    }

    /**
     * Converts JSON encoded string into a PHP variable.
     *
     * @param string $json  JSON string
     * @param bool   $assoc returned objects will be converted into associative arrays
     *
     * @return mixed the value encoded in json in appropriate PHP type
     *
     * @throws ParsingException
     *
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
     */
    protected static function parse($json, $assoc = false)
    {
        $falgs = JsonParser::DETECT_KEY_CONFLICTS;

        if ($assoc) {
            $falgs |= JsonParser::PARSE_TO_ASSOC;
        }

        $parser = new JsonParser();

        return $parser->parse($json, $falgs);
    }

    /**
     * Read and decode a JSON file.
     *
     * @see http://php.net/manual/en/function.json-decode.php json_decode documentation
     *
     * @param string $path  the file path
     * @param bool   $assoc returned objects will be converted into associative arrays
     *
     * @return mixed the value encoded in json in appropriate PHP type
     *
     * @throws ResourceException
     * @throws ParsingException
     *
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
     * @SuppressWarnings(PHPMD.StaticAccess)
     */
    public static function call($path, $assoc = false)
    {
        return self::parse(BomUtil::removeBom(self::readFile($path)), $assoc);
    }
}